diff options
Diffstat (limited to 'src/findkey.c')
-rw-r--r-- | src/findkey.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/src/findkey.c b/src/findkey.c index 7638b04..bd9fd83 100644 --- a/src/findkey.c +++ b/src/findkey.c @@ -1,89 +1,109 @@ /* findkey.c - The routine that finds a key entry in the file. */ /* This file is part of GDBM, the GNU data base manager. Copyright (C) 1990-1991, 1993, 2007, 2011, 2013, 2016-2018 Free Software Foundation, Inc. GDBM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GDBM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GDBM. If not, see <http://www.gnu.org/licenses/>. */ /* Include system configuration before all else. */ #include "autoconf.h" #include "gdbmdefs.h" - +int +gdbm_bucket_element_valid_p (GDBM_FILE dbf, int elem_loc) +{ + return + elem_loc < dbf->header->bucket_elems + && dbf->bucket->h_table[elem_loc].hash_value != -1 + && dbf->bucket->h_table[elem_loc].key_size >= 0 + && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer, + dbf->bucket->h_table[elem_loc].key_size) + && dbf->bucket->h_table[elem_loc].data_size >= 0 + && off_t_sum_ok (dbf->bucket->h_table[elem_loc].data_pointer + + dbf->bucket->h_table[elem_loc].key_size, + dbf->bucket->h_table[elem_loc].data_size); +} + /* Read the data found in bucket entry ELEM_LOC in file DBF and return a pointer to it. Also, cache the read value. */ char * _gdbm_read_entry (GDBM_FILE dbf, int elem_loc) { int rc; int key_size; int data_size; off_t file_pos; data_cache_elem *data_ca; - + /* Is it already in the cache? */ if (dbf->cache_entry->ca_data.elem_loc == elem_loc) return dbf->cache_entry->ca_data.dptr; + if (!gdbm_bucket_element_valid_p (dbf, elem_loc)) + { + GDBM_SET_ERRNO (dbf, GDBM_BAD_HASH_TABLE, TRUE); + return NULL; + } + /* Set sizes and pointers. */ key_size = dbf->bucket->h_table[elem_loc].key_size; data_size = dbf->bucket->h_table[elem_loc].data_size; data_ca = &dbf->cache_entry->ca_data; /* Set up the cache. */ if (data_ca->dptr != NULL) free (data_ca->dptr); data_ca->key_size = key_size; data_ca->data_size = data_size; data_ca->elem_loc = elem_loc; data_ca->hash_val = dbf->bucket->h_table[elem_loc].hash_value; if (GDBM_DEBUG_HOOK ("_gdbm_read_entry:malloc-failure")) data_ca->dptr = NULL; else if (key_size + data_size == 0) data_ca->dptr = (char *) malloc (1); else data_ca->dptr = (char *) malloc (key_size + data_size); if (data_ca->dptr == NULL) { GDBM_SET_ERRNO2 (dbf, GDBM_MALLOC_ERROR, FALSE, GDBM_DEBUG_LOOKUP); _gdbm_fatal (dbf, _("malloc error")); return NULL; } /* Read into the cache. */ file_pos = GDBM_DEBUG_OVERRIDE ("_gdbm_read_entry:lseek-failure", __lseek (dbf, dbf->bucket->h_table[elem_loc].data_pointer, SEEK_SET)); if (file_pos != dbf->bucket->h_table[elem_loc].data_pointer) { GDBM_SET_ERRNO2 (dbf, GDBM_FILE_SEEK_ERROR, TRUE, GDBM_DEBUG_LOOKUP); _gdbm_fatal (dbf, _("lseek error")); return NULL; } rc = GDBM_DEBUG_OVERRIDE ("_gdbm_read_entry:read-failure", _gdbm_full_read (dbf, data_ca->dptr, key_size+data_size)); if (rc) { GDBM_DEBUG (GDBM_DEBUG_ERR|GDBM_DEBUG_LOOKUP|GDBM_DEBUG_READ, "%s: error reading entry: %s", dbf->name, gdbm_db_strerror (dbf)); dbf->need_recovery = TRUE; _gdbm_fatal (dbf, gdbm_db_strerror (dbf)); return NULL; } |