diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-05-26 22:17:10 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-05-27 17:16:03 +0200 |
commit | 4011b4ce9a4c4fa505843381d43a1157cf0c782e (patch) | |
tree | 3b12f036a9dabd412a0ada3d6e0c07f44a2dfc91 /src/gdbmstore.c | |
parent | d100aa7a304913fa1692abaa2818418409f3668a (diff) | |
download | gdbm-4011b4ce9a4c4fa505843381d43a1157cf0c782e.tar.gz gdbm-4011b4ce9a4c4fa505843381d43a1157cf0c782e.tar.bz2 |
Additional validation of avail_table.
Verify that avail_table is sorted by size and that each element's
size falls within allowed range.
* src/bucket.c (gdbm_get_bucket): Fix bucket validation. Validate
bucket_avail.
(_gdbm_split_bucket): Check return from _gdbm_free.
* src/falloc.c (adjust_bucket_avail,_gdbm_free): Return error code.
All uses updated.
(pop_avail_block): Fix eventual memory leak. Use gdbm_avail_block_validate.
* src/gdbmdefs.h (gdbm_avail_table_valid_p): Change signature.
* src/gdbmopen.c (gdbm_avail_table_valid_p): Traverse the array verifying
address and size of each element.
(gdbm_avail_block_validate)
(gdbm_bucket_avail_table_validate): New functions.
(validate_header): Remove call to gdbm_avail_block_valid_p. Avail_block
is validated later, after it's been loaded.
Bail out if header->next_block does not equal the file size.
(gdbm_fd_open): Validate avail_block.
* src/gdbmstore.c (_gdbm_store): Check return from _gdbm_free. Avoid
endless loop in case of inconsistent h_table.
* src/gdbmtool.c (_gdbm_print_avail_list): Use gdbm_avail_block_validate.
* src/proto.h: Update.
* tests/gtload.c: Improve error diagnostics.
Diffstat (limited to 'src/gdbmstore.c')
-rw-r--r-- | src/gdbmstore.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/gdbmstore.c b/src/gdbmstore.c index 7b2ed04..2ed1616 100644 --- a/src/gdbmstore.c +++ b/src/gdbmstore.c | |||
@@ -28,12 +28,13 @@ | |||
28 | before returning from this procedure. The FLAGS define the action to | 28 | before returning from this procedure. The FLAGS define the action to |
29 | take when the KEY is already in the database. The value GDBM_REPLACE | 29 | take when the KEY is already in the database. The value GDBM_REPLACE |
30 | asks that the old data be replaced by the new CONTENT. The value | 30 | asks that the old data be replaced by the new CONTENT. The value |
31 | GDBM_INSERT asks that an error be returned and no action taken. A | 31 | GDBM_INSERT asks that an error be returned and no action taken. |
32 | return value of 0 means no errors. A return value of -1 means that | 32 | |
33 | the item was not stored in the data base because the caller was not an | 33 | On success (the item was stored), 0 is returned. If the item could |
34 | official writer. A return value of 0 means that the item was not stored | 34 | not be stored because a matching key already exists and GDBM_REPLACE |
35 | because the argument FLAGS was GDBM_INSERT and the KEY was already in | 35 | was not given, 1 is returned and gdbm_errno (as well as the database |
36 | the database. */ | 36 | errno value) is set to GDBM_CANNOT_REPLACE. Otherwise, if another |
37 | error occurred, -1 is returned. */ | ||
37 | 38 | ||
38 | int | 39 | int |
39 | gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) | 40 | gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) |
@@ -91,7 +92,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) | |||
91 | + dbf->bucket->h_table[elem_loc].data_size; | 92 | + dbf->bucket->h_table[elem_loc].data_size; |
92 | if (free_size != new_size) | 93 | if (free_size != new_size) |
93 | { | 94 | { |
94 | _gdbm_free (dbf, free_adr, free_size); | 95 | if (_gdbm_free (dbf, free_adr, free_size)) |
96 | return -1; | ||
95 | } | 97 | } |
96 | else | 98 | else |
97 | { | 99 | { |
@@ -123,6 +125,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) | |||
123 | /* If this is a new entry in the bucket, we need to do special things. */ | 125 | /* If this is a new entry in the bucket, we need to do special things. */ |
124 | if (elem_loc == -1) | 126 | if (elem_loc == -1) |
125 | { | 127 | { |
128 | int start_loc; | ||
129 | |||
126 | if (dbf->bucket->count == dbf->header->bucket_elems) | 130 | if (dbf->bucket->count == dbf->header->bucket_elems) |
127 | { | 131 | { |
128 | /* Split the current bucket. */ | 132 | /* Split the current bucket. */ |
@@ -131,10 +135,17 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) | |||
131 | } | 135 | } |
132 | 136 | ||
133 | /* Find space to insert into bucket and set elem_loc to that place. */ | 137 | /* Find space to insert into bucket and set elem_loc to that place. */ |
134 | elem_loc = new_hash_val % dbf->header->bucket_elems; | 138 | elem_loc = start_loc = new_hash_val % dbf->header->bucket_elems; |
135 | while (dbf->bucket->h_table[elem_loc].hash_value != -1) | 139 | while (dbf->bucket->h_table[elem_loc].hash_value != -1) |
136 | elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; | 140 | { |
137 | 141 | elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; | |
142 | if (elem_loc == start_loc) | ||
143 | { | ||
144 | GDBM_SET_ERRNO (dbf, GDBM_BAD_HASH_TABLE, TRUE); | ||
145 | return -1; | ||
146 | } | ||
147 | } | ||
148 | |||
138 | /* We now have another element in the bucket. Add the new information.*/ | 149 | /* We now have another element in the bucket. Add the new information.*/ |
139 | dbf->bucket->count++; | 150 | dbf->bucket->count++; |
140 | dbf->bucket->h_table[elem_loc].hash_value = new_hash_val; | 151 | dbf->bucket->h_table[elem_loc].hash_value = new_hash_val; |