Skip to content

Commit

Permalink
Fixed a UT failure that only happened with O3 optimization
Browse files Browse the repository at this point in the history
Signed-off-by: Rain Valentine <[email protected]>
  • Loading branch information
SoftlyRaining committed Oct 25, 2024
1 parent 5129254 commit de10a98
Showing 1 changed file with 23 additions and 5 deletions.
28 changes: 23 additions & 5 deletions src/unit/test_hashset.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,9 @@ int test_safe_iterator(int argc, char **argv, int flags) {
/* A set of longs, i.e. pointer-sized values. */
hashsetType type = {0};
hashset *s = hashsetCreate(&type);
long j;

/* Populate */
for (j = 0; j < count; j++) {
for (long j = 0; j < count; j++) {
assert(hashsetAdd(s, (void *)j));
}

Expand All @@ -438,7 +437,26 @@ int test_safe_iterator(int argc, char **argv, int flags) {
long num_returned = 0;
hashsetIterator iter;
hashsetInitSafeIterator(&iter, s);
while (hashsetNext(&iter, (void **)&j)) {

/* Important note for directly storing data instead of pointers in hashset:
* This code will probably fail if compiled with -O3, which may reorder
* statements:
*
* long j = 1000;
* while (hashsetNext(&iter, (void **)&j)) {
*
* The cast from long* to void** confuses the compiler, which fails to
* recognize that hashsetNext may change the value of j. In this case it
* reordered hashsetDelete() before hashsetNext() and attempted to delete
* element 1000, which does not exist.
*
* When storing something other than a pointer in hashset, an intermediary
* variable (example below) avoids the problematic cast and clarifies our
* intention for the compiler. */
void* element;
while (hashsetNext(&iter, &element)) {
long j = (long) element;

num_returned++;
if (j < 0 || j >= count * 2) {
printf("Element %ld returned, max == %ld. Num returned: %ld\n", j, count * 2 - 1, num_returned);
Expand All @@ -462,7 +480,7 @@ int test_safe_iterator(int argc, char **argv, int flags) {
/* Check that all elements present during the whole iteration were returned
* exactly once. (Some are deleted after being returned.) */
TEST_ASSERT(num_returned >= count);
for (j = 0; j < count; j++) {
for (long j = 0; j < count; j++) {
if (element_returned[j] != 1) {
printf("Element %ld returned %d times\n", j, element_returned[j]);
return 0;
Expand All @@ -471,7 +489,7 @@ int test_safe_iterator(int argc, char **argv, int flags) {
/* Check that elements inserted during the iteration were returned at most
* once. */
unsigned long num_optional_returned;
for (j = count; j < count * 2; j++) {
for (long j = count; j < count * 2; j++) {
assert(element_returned[j] <= 1);
num_optional_returned += element_returned[j];
}
Expand Down

0 comments on commit de10a98

Please sign in to comment.