2016-05-31 18:41:28 +02:00
|
|
|
/*
|
|
|
|
* QEMU 64-bit address ranges
|
|
|
|
*
|
|
|
|
* Copyright (c) 2015-2016 Red Hat, Inc.
|
|
|
|
*
|
2019-01-23 15:51:23 +01:00
|
|
|
* This program is free software; you can redistribute it and/or
|
2016-05-31 18:41:28 +02:00
|
|
|
* modify it under the terms of the GNU General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
2019-01-23 15:51:23 +01:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2016-05-31 18:41:28 +02:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2019-01-23 15:51:23 +01:00
|
|
|
* General Public License for more details.
|
2016-05-31 18:41:28 +02:00
|
|
|
*
|
2019-01-23 15:51:23 +01:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2016-05-31 18:41:28 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
#include "qemu/range.h"
|
|
|
|
|
2023-10-19 15:45:11 +02:00
|
|
|
int range_compare(Range *a, Range *b)
|
2016-05-31 18:41:28 +02:00
|
|
|
{
|
2016-07-01 13:47:48 +02:00
|
|
|
assert(!range_is_empty(a) && !range_is_empty(b));
|
|
|
|
|
|
|
|
/* Careful, avoid wraparound */
|
|
|
|
if (b->lob && b->lob - 1 > a->upb) {
|
2016-05-31 18:41:29 +02:00
|
|
|
return -1;
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
}
|
2016-07-01 13:47:48 +02:00
|
|
|
if (a->lob && a->lob - 1 > b->upb) {
|
2016-05-31 18:41:29 +02:00
|
|
|
return 1;
|
|
|
|
}
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
return 0;
|
2016-05-31 18:41:29 +02:00
|
|
|
}
|
|
|
|
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
/* Insert @data into @list of ranges; caller no longer owns @data */
|
2016-05-31 18:41:29 +02:00
|
|
|
GList *range_list_insert(GList *list, Range *data)
|
2016-05-31 18:41:28 +02:00
|
|
|
{
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
GList *l;
|
2016-05-31 18:41:28 +02:00
|
|
|
|
2016-07-01 13:47:47 +02:00
|
|
|
assert(!range_is_empty(data));
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
|
|
|
|
/* Skip all list elements strictly less than data */
|
|
|
|
for (l = list; l && range_compare(l->data, data) < 0; l = l->next) {
|
2016-05-31 18:41:28 +02:00
|
|
|
}
|
|
|
|
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
if (!l || range_compare(l->data, data) > 0) {
|
|
|
|
/* Rest of the list (if any) is strictly greater than @data */
|
|
|
|
return g_list_insert_before(list, l, data);
|
2016-05-31 18:41:28 +02:00
|
|
|
}
|
|
|
|
|
qapi: Fix memleak in string visitors on int lists
Commit 7f8f9ef1 introduced the ability to store a list of
integers as a sorted list of ranges, but when merging ranges,
it leaks one or more ranges. It was also using range_get_last()
incorrectly within range_compare() (a range is a start/end pair,
but range_get_last() is for start/len pairs), and will also
mishandle a range ending in UINT64_MAX (remember, we document
that no range covers 2**64 bytes, but that ranges that end on
UINT64_MAX have end < begin).
The whole merge algorithm was rather complex, and included
unnecessary passes over data within glib functions, and enough
indirection to make it hard to easily plug the data leaks.
Since we are already hard-coding things to a list of ranges,
just rewrite the thing to open-code the traversal and
comparisons, by making the range_compare() helper function give
us an answer that is easier to use, at which point we avoid the
need to pass any callbacks to g_list_*(). Then by reusing
range_extend() instead of duplicating effort with range_merge(),
we cover the corner cases correctly.
Drop the now-unused range_merge() and ranges_can_merge().
Doing this lets test-string-{input,output}-visitor pass under
valgrind without leaks.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1464712890-14262-4-git-send-email-eblake@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[Comment hoisted out of loop]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-05-31 18:41:30 +02:00
|
|
|
/* Current list element overlaps @data, merge the two */
|
|
|
|
range_extend(l->data, data);
|
|
|
|
g_free(data);
|
|
|
|
|
|
|
|
/* Merge any subsequent list elements that now also overlap */
|
|
|
|
while (l->next && range_compare(l->data, l->next->data) == 0) {
|
|
|
|
GList *new_l;
|
|
|
|
|
|
|
|
range_extend(l->data, l->next->data);
|
|
|
|
g_free(l->next->data);
|
|
|
|
new_l = g_list_delete_link(list, l->next);
|
|
|
|
assert(new_l == list);
|
2016-05-31 18:41:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
2023-10-19 15:45:14 +02:00
|
|
|
|
|
|
|
static inline
|
|
|
|
GList *append_new_range(GList *list, uint64_t lob, uint64_t upb)
|
|
|
|
{
|
|
|
|
Range *new = g_new0(Range, 1);
|
|
|
|
|
|
|
|
range_set_bounds(new, lob, upb);
|
|
|
|
return g_list_append(list, new);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void range_inverse_array(GList *in, GList **rev,
|
|
|
|
uint64_t low, uint64_t high)
|
|
|
|
{
|
|
|
|
Range *r, *rn;
|
|
|
|
GList *l = in, *out = *rev;
|
|
|
|
|
|
|
|
for (l = in; l && range_upb(l->data) < low; l = l->next) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!l) {
|
|
|
|
out = append_new_range(out, low, high);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
r = (Range *)l->data;
|
|
|
|
|
|
|
|
/* first range lob is greater than min, insert a first range */
|
|
|
|
if (range_lob(r) > low) {
|
|
|
|
out = append_new_range(out, low, MIN(range_lob(r) - 1, high));
|
|
|
|
}
|
|
|
|
|
2023-11-14 17:11:33 +01:00
|
|
|
/* insert a range in between each original range until we reach high */
|
2023-10-19 15:45:14 +02:00
|
|
|
for (; l->next; l = l->next) {
|
|
|
|
r = (Range *)l->data;
|
|
|
|
rn = (Range *)l->next->data;
|
|
|
|
if (range_lob(r) >= high) {
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
if (range_compare(r, rn)) {
|
|
|
|
out = append_new_range(out, range_upb(r) + 1,
|
|
|
|
MIN(range_lob(rn) - 1, high));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* last range */
|
|
|
|
r = (Range *)l->data;
|
|
|
|
|
|
|
|
/* last range upb is less than max, insert a last range */
|
|
|
|
if (range_upb(r) < high) {
|
|
|
|
out = append_new_range(out, range_upb(r) + 1, high);
|
|
|
|
}
|
|
|
|
exit:
|
|
|
|
*rev = out;
|
|
|
|
}
|