From 036befb376dadce543c48327ad8f4761a772a7af Mon Sep 17 00:00:00 2001 From: Michael Schroeder Date: Tue, 31 Mar 2009 12:37:43 +0200 Subject: [PATCH] 1 - fix potential NULL deref in srcrpm handling 2 - clean up and fix suggested/recommended list creation code --- src/solver.c | 371 ++++++++++++++++++++++++++++++----------------------- tools/repo_rpmdb.c | 4 +- tools/repo_rpmmd.c | 5 +- 3 files changed, 218 insertions(+), 162 deletions(-) diff --git a/src/solver.c b/src/solver.c index 7d586e1..3eb9aee 100644 --- a/src/solver.c +++ b/src/solver.c @@ -4080,6 +4080,10 @@ create_obsolete_index(Solver *solv) /*------------------------------------------------------------------- * * remove disabled conflicts + * + * purpose: update the decisionmap after some rules were disabled. + * this is used to calculate the suggested/recommended package list. + * Also returns a "removed" list to undo the discisionmap changes. */ static void @@ -4178,6 +4182,14 @@ removedisabledconflicts(Solver *solv, Queue *removed) } } +static inline void +undo_removedisabledconflicts(Solver *solv, Queue *removed) +{ + int i; + for (i = 0; i < removed->count; i += 2) + solv->decisionmap[removed->elements[i]] = removed->elements[i + 1]; +} + /*------------------------------------------------------------------- * @@ -4404,6 +4416,201 @@ addduprules(Solver *solv, Map *addedmap) solv->duprules_end = solv->nrules; } + +static void +findrecommendedsuggested(Solver *solv) +{ + Pool *pool = solv->pool; + Queue redoq, disabledq; + int goterase, i; + Solvable *s; + Rule *r; + Map obsmap; + + map_init(&obsmap, pool->nsolvables); + if (solv->installed) + { + Id obs, *obsp, p, po, ppo; + for (p = solv->installed->start; p < solv->installed->end; p++) + { + s = pool->solvables + p; + if (s->repo != solv->installed || !s->obsoletes) + continue; + if (solv->decisionmap[p] <= 0) + continue; + if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p)) + continue; + obsp = s->repo->idarraydata + s->obsoletes; + /* foreach obsoletes */ + while ((obs = *obsp++) != 0) + FOR_PROVIDES(po, ppo, obs) + MAPSET(&obsmap, po); + } + } + + queue_init(&redoq); + queue_init(&disabledq); + goterase = 0; + /* disable all erase jobs (including weak "keep uninstalled" rules) */ + for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) + { + if (r->d < 0) /* disabled ? */ + continue; + if (r->p >= 0) /* install job? */ + continue; + queue_push(&disabledq, i); + disablerule(solv, r); + goterase++; + } + + if (goterase) + { + enabledisablelearntrules(solv); + removedisabledconflicts(solv, &redoq); + } + + /* + * find recommended packages + */ + + /* if redoq.count == 0 we already found all recommended in the + * solver run */ + if (redoq.count || solv->dontinstallrecommended || !solv->dontshowinstalledrecommended || solv->ignorealreadyrecommended) + { + Id rec, *recp, p, pp; + + /* create map of all recommened packages */ + solv->recommends_index = -1; + MAPZERO(&solv->recommendsmap); + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p < 0) + continue; + s = pool->solvables + p; + if (s->recommends) + { + recp = s->repo->idarraydata + s->recommends; + while ((rec = *recp++) != 0) + { + FOR_PROVIDES(p, pp, rec) + if (solv->decisionmap[p] > 0) + break; + if (p) + { + if (!solv->dontshowinstalledrecommended) + { + FOR_PROVIDES(p, pp, rec) + if (solv->decisionmap[p] > 0) + MAPSET(&solv->recommendsmap, p); + } + continue; /* p != 0: already fulfilled */ + } + FOR_PROVIDES(p, pp, rec) + MAPSET(&solv->recommendsmap, p); + } + } + } + for (i = 1; i < pool->nsolvables; i++) + { + if (solv->decisionmap[i] < 0) + continue; + if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended) + continue; + if (MAPTST(&obsmap, i)) + continue; + s = pool->solvables + i; + if (!MAPTST(&solv->recommendsmap, i)) + { + if (!s->supplements) + continue; + if (!pool_installable(pool, s)) + continue; + if (!solver_is_supplementing(solv, s)) + continue; + } + if (solv->dontinstallrecommended) + queue_push(&solv->recommendations, i); + else + queue_pushunique(&solv->recommendations, i); + } + /* we use MODE_SUGGEST here so that repo prio is ignored */ + policy_filter_unwanted(solv, &solv->recommendations, POLICY_MODE_SUGGEST); + } + + /* + * find suggested packages + */ + + if (1) + { + Id sug, *sugp, p, pp; + + /* create map of all suggests that are still open */ + solv->recommends_index = -1; + MAPZERO(&solv->suggestsmap); + for (i = 0; i < solv->decisionq.count; i++) + { + p = solv->decisionq.elements[i]; + if (p < 0) + continue; + s = pool->solvables + p; + if (s->suggests) + { + sugp = s->repo->idarraydata + s->suggests; + while ((sug = *sugp++) != 0) + { + FOR_PROVIDES(p, pp, sug) + if (solv->decisionmap[p] > 0) + break; + if (p) + { + if (!solv->dontshowinstalledrecommended) + { + FOR_PROVIDES(p, pp, sug) + if (solv->decisionmap[p] > 0) + MAPSET(&solv->suggestsmap, p); + } + continue; /* already fulfilled */ + } + FOR_PROVIDES(p, pp, sug) + MAPSET(&solv->suggestsmap, p); + } + } + } + for (i = 1; i < pool->nsolvables; i++) + { + if (solv->decisionmap[i] < 0) + continue; + if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended) + continue; + if (MAPTST(&obsmap, i)) + continue; + s = pool->solvables + i; + if (!MAPTST(&solv->suggestsmap, i)) + { + if (!s->enhances) + continue; + if (!pool_installable(pool, s)) + continue; + if (!solver_is_enhancing(solv, s)) + continue; + } + queue_push(&solv->suggestions, i); + } + policy_filter_unwanted(solv, &solv->suggestions, POLICY_MODE_SUGGEST); + } + + /* undo removedisabledconflicts */ + if (redoq.count) + undo_removedisabledconflicts(solv, &redoq); + + /* undo job rule disabling */ + for (i = 0; i < disabledq.count; i++) + enablerule(solv, solv->rules + disabledq.elements[i]); + map_free(&obsmap); +} + /* * * solve job queue @@ -4420,9 +4627,8 @@ solver_solve(Solver *solv, Queue *job) Map addedmap; /* '1' == have rpm-rules for solvable */ Map installcandidatemap; Id how, what, select, name, weak, p, pp, d; - Queue q, redoq; + Queue q; Solvable *s; - int goterase; Rule *r; int now, solve_start; int hasdupjob = 0; @@ -4886,169 +5092,20 @@ solver_solve(Solver *solv, Queue *job) run_solver(solv, 1, solv->dontinstallrecommended ? 0 : 1); POOL_DEBUG(SAT_DEBUG_STATS, "solver took %d ms\n", sat_timems(now)); - queue_init(&redoq); - goterase = 0; - /* disable all erase jobs (including weak "keep uninstalled" rules) */ - for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++) - { - if (r->d < 0) /* disabled ? */ - continue; - if (r->p > 0) /* install job? */ - continue; - disablerule(solv, r); - goterase++; - } - - if (goterase) - { - enabledisablelearntrules(solv); - removedisabledconflicts(solv, &redoq); - } - /* - * find recommended packages + * calculate recommended/suggested packages */ - - /* if redoq.count == 0 we already found all recommended in the - * solver run */ - if (redoq.count || solv->dontinstallrecommended || !solv->dontshowinstalledrecommended || solv->ignorealreadyrecommended) - { - Id rec, *recp, p, pp; - - /* create map of all recommened packages */ - solv->recommends_index = -1; - MAPZERO(&solv->recommendsmap); - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (s->recommends) - { - recp = s->repo->idarraydata + s->recommends; - while ((rec = *recp++) != 0) - { - FOR_PROVIDES(p, pp, rec) - if (solv->decisionmap[p] > 0) - break; - if (p) - { - if (!solv->dontshowinstalledrecommended) - { - FOR_PROVIDES(p, pp, rec) - if (solv->decisionmap[p] > 0) - MAPSET(&solv->recommendsmap, p); - } - continue; /* p != 0: already fulfilled */ - } - FOR_PROVIDES(p, pp, rec) - MAPSET(&solv->recommendsmap, p); - } - } - } - for (i = 1; i < pool->nsolvables; i++) - { - if (solv->decisionmap[i] < 0) - continue; - if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended) - continue; - s = pool->solvables + i; - if (!MAPTST(&solv->recommendsmap, i)) - { - if (!s->supplements) - continue; - if (!pool_installable(pool, s)) - continue; - if (!solver_is_supplementing(solv, s)) - continue; - } - if (solv->dontinstallrecommended) - queue_push(&solv->recommendations, i); - else - queue_pushunique(&solv->recommendations, i); - } - /* we use MODE_SUGGEST here so that repo prio is ignored */ - policy_filter_unwanted(solv, &solv->recommendations, POLICY_MODE_SUGGEST); - } + findrecommendedsuggested(solv); /* - * find suggested packages + * if unsolvable, prepare solutions */ - - if (1) - { - Id sug, *sugp, p, pp; - - /* create map of all suggests that are still open */ - solv->recommends_index = -1; - MAPZERO(&solv->suggestsmap); - for (i = 0; i < solv->decisionq.count; i++) - { - p = solv->decisionq.elements[i]; - if (p < 0) - continue; - s = pool->solvables + p; - if (s->suggests) - { - sugp = s->repo->idarraydata + s->suggests; - while ((sug = *sugp++) != 0) - { - FOR_PROVIDES(p, pp, sug) - if (solv->decisionmap[p] > 0) - break; - if (p) - { - if (!solv->dontshowinstalledrecommended) - { - FOR_PROVIDES(p, pp, sug) - if (solv->decisionmap[p] > 0) - MAPSET(&solv->suggestsmap, p); - } - continue; /* already fulfilled */ - } - FOR_PROVIDES(p, pp, sug) - MAPSET(&solv->suggestsmap, p); - } - } - } - for (i = 1; i < pool->nsolvables; i++) - { - if (solv->decisionmap[i] < 0) - continue; - if (solv->decisionmap[i] > 0 && solv->dontshowinstalledrecommended) - continue; - s = pool->solvables + i; - if (!MAPTST(&solv->suggestsmap, i)) - { - if (!s->enhances) - continue; - if (!pool_installable(pool, s)) - continue; - if (!solver_is_enhancing(solv, s)) - continue; - } - queue_push(&solv->suggestions, i); - } - policy_filter_unwanted(solv, &solv->suggestions, POLICY_MODE_SUGGEST); - } - - if (redoq.count) - { - /* restore decisionmap */ - for (i = 0; i < redoq.count; i += 2) - solv->decisionmap[redoq.elements[i]] = redoq.elements[i + 1]; - } - - /* - * if unsolvable, prepare solutions - */ - if (solv->problems.count) { + Queue redoq; int recocount = solv->recommendations.count; solv->recommendations.count = 0; /* so that revert() doesn't mess with it */ - queue_empty(&redoq); + queue_init(&redoq); for (i = 0; i < solv->decisionq.count; i++) { Id p = solv->decisionq.elements[i]; @@ -5068,9 +5125,9 @@ solver_solve(Solver *solv, Queue *job) solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2]; } solv->recommendations.count = recocount; + queue_free(&redoq); } - queue_free(&redoq); POOL_DEBUG(SAT_DEBUG_STATS, "final solver statistics: %d learned rules, %d unsolvable\n", solv->stats_learned, solv->stats_unsolvable); POOL_DEBUG(SAT_DEBUG_STATS, "solver_solve took %d ms\n", sat_timems(solve_start)); } diff --git a/tools/repo_rpmdb.c b/tools/repo_rpmdb.c index f400c1a..1a49d3a 100644 --- a/tools/repo_rpmdb.c +++ b/tools/repo_rpmdb.c @@ -782,11 +782,11 @@ addsourcerpm(Pool *pool, Repodata *data, Id handle, char *sourcerpm, char *name, repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_NOSRC); else repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, strn2id(pool, sarch, strlen(sarch) - 4, 1)); - if (!strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) + if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) repodata_set_void(data, handle, SOLVABLE_SOURCEEVR); else repodata_set_id(data, handle, SOLVABLE_SOURCEEVR, strn2id(pool, sevr, sarch - sevr - 1, 1)); - if (!strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - 1] == 0) + if (name && !strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - 1] == 0) repodata_set_void(data, handle, SOLVABLE_SOURCENAME); else repodata_set_id(data, handle, SOLVABLE_SOURCENAME, strn2id(pool, sourcerpm, sevr - sourcerpm - 1, 1)); diff --git a/tools/repo_rpmmd.c b/tools/repo_rpmmd.c index ec50b16..c72aba5 100644 --- a/tools/repo_rpmmd.c +++ b/tools/repo_rpmmd.c @@ -594,12 +594,11 @@ set_sourcerpm(Repodata *data, Solvable *s, Id handle, char *sourcerpm) repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, ARCH_NOSRC); else repodata_set_constantid(data, handle, SOLVABLE_SOURCEARCH, strn2id(pool, sarch, strlen(sarch) - 4, 1)); - if (!strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) + if (evr && !strncmp(sevr, evr, sarch - sevr - 1) && evr[sarch - sevr - 1] == 0) repodata_set_void(data, handle, SOLVABLE_SOURCEEVR); else repodata_set_id(data, handle, SOLVABLE_SOURCEEVR, strn2id(pool, sevr, sarch - sevr - 1, 1)); - if (!strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - - 1] == 0) + if (name && !strncmp(sourcerpm, name, sevr - sourcerpm - 1) && name[sevr - sourcerpm - 1] == 0) repodata_set_void(data, handle, SOLVABLE_SOURCENAME); else repodata_set_id(data, handle, SOLVABLE_SOURCENAME, strn2id(pool, sourcerpm, sevr - sourcerpm - 1, 1)); -- 2.7.4