In sync_db_populate() and local_db_populate(), a NULL db->pkgcache is not handled. This not only involves unnecessary operations, but also potentially merge sorting db->pkgcache->list which does not even exist in the case that db->pkgcache is NULL. This may lead to serious issues since alpm_list_msort calls alpm_list_nth which will dereference invalid pointers. Thus, db->pkgcache is checked during local/sync db_populate calls. For this purpose, PM_ERR_DB_PKGCACHE_NULL error is added to _pmerrno_t and taken care of in alpm_strerror(). In addition, common code between _alpm_pkghash_add() and _alpm_pkghash_add_sorted() is refactored out to _alpm_pkghash_add_pkg(). The 2 functions are now wrappers around _alpm_pkghash_add_pkg(). Signed-off-by: Pang Yan Han <pangyanhan@gmail.com> --- Please give me advice on this as to whether it needs tweaking or if it won't be accepted. Thanks! lib/libalpm/alpm.h | 1 + lib/libalpm/be_local.c | 4 ++++ lib/libalpm/be_sync.c | 8 +++++++- lib/libalpm/db.c | 1 + lib/libalpm/error.c | 2 ++ lib/libalpm/pkghash.c | 46 +++++++++++++++------------------------------- lib/libalpm/pkghash.h | 1 + 7 files changed, 31 insertions(+), 32 deletions(-) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 7fec293..57c68bd 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -501,6 +501,7 @@ enum _pmerrno_t { PM_ERR_DB_NOT_FOUND, PM_ERR_DB_WRITE, PM_ERR_DB_REMOVE, + PM_ERR_DB_PKGCACHE_NULL, /* Servers */ PM_ERR_SERVER_BAD_URL, PM_ERR_SERVER_NONE, diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c index c5b2498..c7980f9 100644 --- a/lib/libalpm/be_local.c +++ b/lib/libalpm/be_local.c @@ -393,6 +393,10 @@ static int local_db_populate(pmdb_t *db) /* initialize hash at 50% full */ db->pkgcache = _alpm_pkghash_create(est_count * 2); + if(db->pkgcache == NULL){ + closedir(dbdir); + RET_ERR(PM_ERR_DB_PKGCACHE_NULL, -1); + } while((ent = readdir(dbdir)) != NULL) { const char *name = ent->d_name; diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c index 4ad045c..853ad30 100644 --- a/lib/libalpm/be_sync.c +++ b/lib/libalpm/be_sync.c @@ -234,6 +234,9 @@ static int sync_db_populate(pmdb_t *db) /* initialize hash at 66% full */ db->pkgcache = _alpm_pkghash_create(est_count * 3 / 2); + if(db->pkgcache == NULL) { + RET_ERR(PM_ERR_DB_PKGCACHE_NULL, -1); + } while(archive_read_next_header(archive, &entry) == ARCHIVE_OK) { const struct stat *st; @@ -348,6 +351,9 @@ static int sync_db_read(pmdb_t *db, struct archive *archive, if(likely_pkg && strcmp(likely_pkg->name, pkgname) == 0) { pkg = likely_pkg; } else { + if(db->pkgcache == NULL) { + RET_ERR(PM_ERR_DB_PKGCACHE_NULL, -1); + } pkg = _alpm_pkghash_find(db->pkgcache, pkgname); } if(pkg == NULL) { @@ -459,10 +465,10 @@ pmdb_t *_alpm_db_register_sync(const char *treename) _alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename); db = _alpm_db_new(treename, 0); - db->ops = &sync_db_ops; if(db == NULL) { RET_ERR(PM_ERR_DB_CREATE, NULL); } + db->ops = &sync_db_ops; handle->dbs_sync = alpm_list_add(handle->dbs_sync, db); return(db); diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c index 02f8282..d43a16b 100644 --- a/lib/libalpm/db.c +++ b/lib/libalpm/db.c @@ -370,6 +370,7 @@ pmdb_t *_alpm_db_new(const char *treename, int is_local) CALLOC(db, 1, sizeof(pmdb_t), RET_ERR(PM_ERR_MEMORY, NULL)); STRDUP(db->treename, treename, RET_ERR(PM_ERR_MEMORY, NULL)); db->is_local = is_local; + db->pkgcache_loaded = 0; return(db); } diff --git a/lib/libalpm/error.c b/lib/libalpm/error.c index 2cc6685..5b48c89 100644 --- a/lib/libalpm/error.c +++ b/lib/libalpm/error.c @@ -81,6 +81,8 @@ const char SYMEXPORT *alpm_strerror(int err) return _("could not update database"); case PM_ERR_DB_REMOVE: return _("could not remove database entry"); + case PM_ERR_DB_PKGCACHE_NULL: + return _("could not initialize database package cache"); /* Servers */ case PM_ERR_SERVER_BAD_URL: return _("invalid url for server"); diff --git a/lib/libalpm/pkghash.c b/lib/libalpm/pkghash.c index 5480527..7006888 100644 --- a/lib/libalpm/pkghash.c +++ b/lib/libalpm/pkghash.c @@ -150,6 +150,16 @@ static pmpkghash_t *rehash(pmpkghash_t *oldhash) pmpkghash_t *_alpm_pkghash_add(pmpkghash_t *hash, pmpkg_t *pkg) { + return(_alpm_pkghash_add_pkg(hash, pkg, 0)); +} + +pmpkghash_t *_alpm_pkghash_add_sorted(pmpkghash_t *hash, pmpkg_t *pkg) +{ + return(_alpm_pkghash_add_pkg(hash, pkg, 1)); +} + +pmpkghash_t *_alpm_pkghash_add_pkg(pmpkghash_t *hash, pmpkg_t *pkg, int sorted) +{ alpm_list_t *ptr; size_t position; @@ -173,40 +183,13 @@ pmpkghash_t *_alpm_pkghash_add(pmpkghash_t *hash, pmpkg_t *pkg) ptr->prev = ptr; hash->hash_table[position] = ptr; - hash->list = alpm_list_join(hash->list, ptr); - hash->entries += 1; - - return(hash); -} - -pmpkghash_t *_alpm_pkghash_add_sorted(pmpkghash_t *hash, pmpkg_t *pkg) -{ - if(!hash) { - return(_alpm_pkghash_add(hash, pkg)); - } - - alpm_list_t *ptr; - size_t position; - - if((hash->entries + 1) / MAX_HASH_LOAD > hash->buckets) { - hash = rehash(hash); + if(!sorted){ + hash->list = alpm_list_join(hash->list, ptr); + }else{ + hash->list = alpm_list_mmerge(hash->list, ptr, _alpm_pkg_cmp); } - position = get_hash_position(pkg->name_hash, hash); - - ptr = calloc(1, sizeof(alpm_list_t)); - if(ptr == NULL) { - return(hash); - } - - ptr->data = pkg; - ptr->next = NULL; - ptr->prev = ptr; - - hash->hash_table[position] = ptr; - hash->list = alpm_list_mmerge(hash->list, ptr, _alpm_pkg_cmp); hash->entries += 1; - return(hash); } @@ -344,3 +327,4 @@ pmpkg_t *_alpm_pkghash_find(pmpkghash_t *hash, const char *name) return(NULL); } +/* vim: set ts=2 sw=2 noet: */ diff --git a/lib/libalpm/pkghash.h b/lib/libalpm/pkghash.h index a6c1db7..d63c6f0 100644 --- a/lib/libalpm/pkghash.h +++ b/lib/libalpm/pkghash.h @@ -47,6 +47,7 @@ pmpkghash_t *_alpm_pkghash_create(size_t size); pmpkghash_t *_alpm_pkghash_add(pmpkghash_t *hash, pmpkg_t *pkg); pmpkghash_t *_alpm_pkghash_add_sorted(pmpkghash_t *hash, pmpkg_t *pkg); +pmpkghash_t *_alpm_pkghash_add_pkg(pmpkghash_t *hash, pmpkg_t *pkg, int sorted); pmpkghash_t *_alpm_pkghash_remove(pmpkghash_t *hash, pmpkg_t *pkg, pmpkg_t **data); void _alpm_pkghash_free(pmpkghash_t *hash); -- 1.7.4