aboutsummaryrefslogtreecommitdiff
path: root/src/gdbmstore.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-05-26 22:17:10 +0200
committerSergey Poznyakoff <gray@gnu.org>2018-05-27 17:16:03 +0200
commit4011b4ce9a4c4fa505843381d43a1157cf0c782e (patch)
tree3b12f036a9dabd412a0ada3d6e0c07f44a2dfc91 /src/gdbmstore.c
parentd100aa7a304913fa1692abaa2818418409f3668a (diff)
downloadgdbm-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.c31
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;

Return to:

Send suggestions and report system problems to the System administrator.