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 @@ before returning from this procedure. The FLAGS define the action to take when the KEY is already in the database. The value GDBM_REPLACE asks that the old data be replaced by the new CONTENT. The value - GDBM_INSERT asks that an error be returned and no action taken. A - return value of 0 means no errors. A return value of -1 means that - the item was not stored in the data base because the caller was not an - official writer. A return value of 0 means that the item was not stored - because the argument FLAGS was GDBM_INSERT and the KEY was already in - the database. */ + GDBM_INSERT asks that an error be returned and no action taken. + + On success (the item was stored), 0 is returned. If the item could + not be stored because a matching key already exists and GDBM_REPLACE + was not given, 1 is returned and gdbm_errno (as well as the database + errno value) is set to GDBM_CANNOT_REPLACE. Otherwise, if another + error occurred, -1 is returned. */ int 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) + dbf->bucket->h_table[elem_loc].data_size; if (free_size != new_size) { - _gdbm_free (dbf, free_adr, free_size); + if (_gdbm_free (dbf, free_adr, free_size)) + return -1; } else { @@ -123,6 +125,8 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) /* If this is a new entry in the bucket, we need to do special things. */ if (elem_loc == -1) { + int start_loc; + if (dbf->bucket->count == dbf->header->bucket_elems) { /* Split the current bucket. */ @@ -131,10 +135,17 @@ gdbm_store (GDBM_FILE dbf, datum key, datum content, int flags) } /* Find space to insert into bucket and set elem_loc to that place. */ - elem_loc = new_hash_val % dbf->header->bucket_elems; + elem_loc = start_loc = new_hash_val % dbf->header->bucket_elems; while (dbf->bucket->h_table[elem_loc].hash_value != -1) - elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; - + { + elem_loc = (elem_loc + 1) % dbf->header->bucket_elems; + if (elem_loc == start_loc) + { + GDBM_SET_ERRNO (dbf, GDBM_BAD_HASH_TABLE, TRUE); + return -1; + } + } + /* We now have another element in the bucket. Add the new information.*/ dbf->bucket->count++; dbf->bucket->h_table[elem_loc].hash_value = new_hash_val; |