Prevent attempts to allocate excessive amounts of memory when parsing corrupt ELF...
[external/binutils.git] / gdb / bcache.h
1 /* Include file cached obstack implementation.
2    Written by Fred Fish <fnf@cygnus.com>
3    Rewritten by Jim Blandy <jimb@cygnus.com>
4
5    Copyright (C) 1999-2019 Free Software Foundation, Inc.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #ifndef BCACHE_H
23 #define BCACHE_H 1
24
25 /* A bcache is a data structure for factoring out duplication in
26    read-only structures.  You give the bcache some string of bytes S.
27    If the bcache already contains a copy of S, it hands you back a
28    pointer to its copy.  Otherwise, it makes a fresh copy of S, and
29    hands you back a pointer to that.  In either case, you can throw
30    away your copy of S, and use the bcache's.
31
32    The "strings" in question are arbitrary strings of bytes --- they
33    can contain zero bytes.  You pass in the length explicitly when you
34    call the bcache function.
35
36    This means that you can put ordinary C objects in a bcache.
37    However, if you do this, remember that structs can contain `holes'
38    between members, added for alignment.  These bytes usually contain
39    garbage.  If you try to bcache two objects which are identical from
40    your code's point of view, but have different garbage values in the
41    structure's holes, then the bcache will treat them as separate
42    strings, and you won't get the nice elimination of duplicates you
43    were hoping for.  So, remember to memset your structures full of
44    zeros before bcaching them!
45
46    You shouldn't modify the strings you get from a bcache, because:
47
48    - You don't necessarily know who you're sharing space with.  If I
49    stick eight bytes of text in a bcache, and then stick an eight-byte
50    structure in the same bcache, there's no guarantee those two
51    objects don't actually comprise the same sequence of bytes.  If
52    they happen to, the bcache will use a single byte string for both
53    of them.  Then, modifying the structure will change the string.  In
54    bizarre ways.
55
56    - Even if you know for some other reason that all that's okay,
57    there's another problem.  A bcache stores all its strings in a hash
58    table.  If you modify a string's contents, you will probably change
59    its hash value.  This means that the modified string is now in the
60    wrong place in the hash table, and future bcache probes will never
61    find it.  So by mutating a string, you give up any chance of
62    sharing its space with future duplicates.
63
64
65    Size of bcache VS hashtab:
66
67    For bcache, the most critical cost is size (or more exactly the
68    overhead added by the bcache).  It turns out that the bcache is
69    remarkably efficient.
70
71    Assuming a 32-bit system (the hash table slots are 4 bytes),
72    ignoring alignment, and limit strings to 255 bytes (1 byte length)
73    we get ...
74
75    bcache: This uses a separate linked list to track the hash chain.
76    The numbers show roughly 100% occupancy of the hash table and an
77    average chain length of 4.  Spreading the slot cost over the 4
78    chain elements:
79
80    4 (slot) / 4 (chain length) + 1 (length) + 4 (chain) = 6 bytes
81
82    hashtab: This uses a more traditional re-hash algorithm where the
83    chain is maintained within the hash table.  The table occupancy is
84    kept below 75% but we'll assume its perfect:
85
86    4 (slot) x 4/3 (occupancy) +  1 (length) = 6 1/3 bytes
87
88    So a perfect hashtab has just slightly larger than an average
89    bcache.
90
91    It turns out that an average hashtab is far worse.  Two things
92    hurt:
93
94    - Hashtab's occupancy is more like 50% (it ranges between 38% and
95    75%) giving a per slot cost of 4x2 vs 4x4/3.
96
97    - the string structure needs to be aligned to 8 bytes which for
98    hashtab wastes 7 bytes, while for bcache wastes only 3.
99
100    This gives:
101
102    hashtab: 4 x 2 + 1 + 7 = 16 bytes
103
104    bcache 4 / 4 + 1 + 4 + 3 = 9 bytes
105
106    The numbers of GDB debugging GDB support this.  ~40% vs ~70% overhead.
107
108
109    Speed of bcache VS hashtab (the half hash hack):
110
111    While hashtab has a typical chain length of 1, bcache has a chain
112    length of round 4.  This means that the bcache will require
113    something like double the number of compares after that initial
114    hash.  In both cases the comparison takes the form:
115
116    a.length == b.length && memcmp (a.data, b.data, a.length) == 0
117
118    That is lengths are checked before doing the memcmp.
119
120    For GDB debugging GDB, it turned out that all lengths were 24 bytes
121    (no C++ so only psymbols were cached) and hence, all compares
122    required a call to memcmp.  As a hack, two bytes of padding
123    (mentioned above) are used to store the upper 16 bits of the
124    string's hash value and then that is used in the comparison vis:
125
126    a.half_hash == b.half_hash && a.length == b.length && memcmp
127    (a.data, b.data, a.length)
128
129    The numbers from GDB debugging GDB show this to be a remarkable
130    100% effective (only necessary length and memcmp tests being
131    performed).
132
133    Mind you, looking at the wall clock, the same GDB debugging GDB
134    showed only marginal speed up (0.780 vs 0.773s).  Seems GDB is too
135    busy doing something else :-(
136   
137 */
138
139 struct bstring;
140
141 /* The hash functions */
142 extern unsigned long hash (const void *addr, int length);
143 extern unsigned long hash_continue (const void *addr, int length,
144                                     unsigned long h);
145
146 struct bcache
147 {
148   /* Allocate a bcache.  HASH_FN and COMPARE_FN can be used to pass in
149      custom hash, and compare functions to be used by this bcache.  If
150      HASH_FUNCTION is NULL hash() is used and if COMPARE_FUNCTION is
151      NULL memcmp() is used.  */
152
153   explicit bcache (unsigned long (*hash_fn)(const void *,
154                                             int length) = nullptr,
155                    int (*compare_fn)(const void *, const void *,
156                                      int length) = nullptr)
157     : m_hash_function (hash_fn == nullptr ? hash : hash_fn),
158       m_compare_function (compare_fn == nullptr ? compare : compare_fn)
159   {
160   }
161
162   ~bcache ();
163
164   /* Find a copy of the LENGTH bytes at ADDR in BCACHE.  If BCACHE has
165      never seen those bytes before, add a copy of them to BCACHE.  In
166      either case, return a pointer to BCACHE's copy of that string.
167      Since the cached value is ment to be read-only, return a const
168      buffer.  If ADDED is not NULL, set *ADDED to true if the bytes
169      were newly added to the cache, or to false if the bytes were
170      found in the cache.  */
171
172   const void *insert (const void *addr, int length, int *added = nullptr);
173
174   /* Print statistics on this bcache's memory usage and efficacity at
175      eliminating duplication.  TYPE should be a string describing the
176      kind of data this bcache holds.  Statistics are printed using
177      `printf_filtered' and its ilk.  */
178   void print_statistics (const char *type);
179   int memory_used ();
180
181 private:
182
183   /* All the bstrings are allocated here.  */
184   struct obstack m_cache {};
185
186   /* How many hash buckets we're using.  */
187   unsigned int m_num_buckets = 0;
188
189   /* Hash buckets.  This table is allocated using malloc, so when we
190      grow the table we can return the old table to the system.  */
191   struct bstring **m_bucket = nullptr;
192
193   /* Statistics.  */
194   unsigned long m_unique_count = 0;     /* number of unique strings */
195   long m_total_count = 0;       /* total number of strings cached, including dups */
196   long m_unique_size = 0;       /* size of unique strings, in bytes */
197   long m_total_size = 0;      /* total number of bytes cached, including dups */
198   long m_structure_size = 0;    /* total size of bcache, including infrastructure */
199   /* Number of times that the hash table is expanded and hence
200      re-built, and the corresponding number of times that a string is
201      [re]hashed as part of entering it into the expanded table.  The
202      total number of hashes can be computed by adding TOTAL_COUNT to
203      expand_hash_count.  */
204   unsigned long m_expand_count = 0;
205   unsigned long m_expand_hash_count = 0;
206   /* Number of times that the half-hash compare hit (compare the upper
207      16 bits of hash values) hit, but the corresponding combined
208      length/data compare missed.  */
209   unsigned long m_half_hash_miss_count = 0;
210
211   /* Hash function to be used for this bcache object.  */
212   unsigned long (*m_hash_function)(const void *addr, int length);
213
214   /* Compare function to be used for this bcache object.  */
215   int (*m_compare_function)(const void *, const void *, int length);
216
217   /* Default compare function.  */
218   static int compare (const void *addr1, const void *addr2, int length);
219
220   /* Expand the hash table.  */
221   void expand_hash_table ();
222 };
223
224 #endif /* BCACHE_H */