forked from u-boot/u-boot
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
hashtable: fix environment variable corruption
Only first previously deleted entry was recognized, leading hsearch_r to think that there was no previously deleted entry. It then conluded that a free entry was found, even if there were no free entries and it overwrote a random entry. This patch makes sure all deleted or free entries are always found and also introduces constants for the 0 and -1 numbers. Unit tests to excersise a simple hash table usage and catch the corruption were added. To trash your environment, simply run this loop: setenv i 0 while true; do setenv v_$i $i setenv v_$i setexpr i $i + 1 done Signed-off-by: Roman Kapl <[email protected]>
- Loading branch information
Showing
3 changed files
with
136 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ | |
|
||
obj-y += cmd_ut_env.o | ||
obj-y += attr.o | ||
obj-y += hashtable.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* (C) Copyright 2019 | ||
* Roman Kapl, SYSGO, [email protected] | ||
*/ | ||
|
||
#include <common.h> | ||
#include <command.h> | ||
#include <search.h> | ||
#include <stdio.h> | ||
#include <test/env.h> | ||
#include <test/ut.h> | ||
|
||
#define SIZE 32 | ||
#define ITERATIONS 10000 | ||
|
||
static int htab_fill(struct unit_test_state *uts, | ||
struct hsearch_data *htab, size_t size) | ||
{ | ||
size_t i; | ||
ENTRY item; | ||
ENTRY *ritem; | ||
char key[20]; | ||
|
||
for (i = 0; i < size; i++) { | ||
sprintf(key, "%d", (int)i); | ||
item.callback = NULL; | ||
item.data = key; | ||
item.flags = 0; | ||
item.key = key; | ||
ut_asserteq(1, hsearch_r(item, ENTER, &ritem, htab, 0)); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int htab_check_fill(struct unit_test_state *uts, | ||
struct hsearch_data *htab, size_t size) | ||
{ | ||
size_t i; | ||
ENTRY item; | ||
ENTRY *ritem; | ||
char key[20]; | ||
|
||
for (i = 0; i < size; i++) { | ||
sprintf(key, "%d", (int)i); | ||
item.callback = NULL; | ||
item.flags = 0; | ||
item.data = key; | ||
item.key = key; | ||
hsearch_r(item, FIND, &ritem, htab, 0); | ||
ut_assert(ritem); | ||
ut_asserteq_str(key, ritem->key); | ||
ut_asserteq_str(key, ritem->data); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int htab_create_delete(struct unit_test_state *uts, | ||
struct hsearch_data *htab, size_t iterations) | ||
{ | ||
size_t i; | ||
ENTRY item; | ||
ENTRY *ritem; | ||
char key[20]; | ||
|
||
for (i = 0; i < iterations; i++) { | ||
sprintf(key, "cd-%d", (int)i); | ||
item.callback = NULL; | ||
item.flags = 0; | ||
item.data = key; | ||
item.key = key; | ||
hsearch_r(item, ENTER, &ritem, htab, 0); | ||
ritem = NULL; | ||
|
||
hsearch_r(item, FIND, &ritem, htab, 0); | ||
ut_assert(ritem); | ||
ut_asserteq_str(key, ritem->key); | ||
ut_asserteq_str(key, ritem->data); | ||
|
||
ut_asserteq(1, hdelete_r(key, htab, 0)); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/* Completely fill up the hash table */ | ||
static int env_test_htab_fill(struct unit_test_state *uts) | ||
{ | ||
struct hsearch_data htab; | ||
|
||
memset(&htab, 0, sizeof(htab)); | ||
ut_asserteq(1, hcreate_r(SIZE, &htab)); | ||
|
||
ut_assertok(htab_fill(uts, &htab, SIZE)); | ||
ut_assertok(htab_check_fill(uts, &htab, SIZE)); | ||
ut_asserteq(SIZE, htab.filled); | ||
|
||
hdestroy_r(&htab); | ||
return 0; | ||
} | ||
|
||
ENV_TEST(env_test_htab_fill, 0); | ||
|
||
/* Fill the hashtable up halfway an repeateadly delete/create elements | ||
* and check for corruption | ||
*/ | ||
static int env_test_htab_deletes(struct unit_test_state *uts) | ||
{ | ||
struct hsearch_data htab; | ||
|
||
memset(&htab, 0, sizeof(htab)); | ||
ut_asserteq(1, hcreate_r(SIZE, &htab)); | ||
|
||
ut_assertok(htab_fill(uts, &htab, SIZE / 2)); | ||
ut_assertok(htab_create_delete(uts, &htab, ITERATIONS)); | ||
ut_assertok(htab_check_fill(uts, &htab, SIZE / 2)); | ||
ut_asserteq(SIZE / 2, htab.filled); | ||
|
||
hdestroy_r(&htab); | ||
return 0; | ||
} | ||
|
||
ENV_TEST(env_test_htab_deletes, 0); |