Our hdestroy implementation was non-conformant because it freed the key of

each entry. Add a new function hdestroy1 that allows the user to control
what gets freed. Pointed out by Pedro Giffuni at FreeBSD.
This commit is contained in:
christos 2014-07-20 13:34:17 +00:00
parent d42187770d
commit 842ee049dd
4 changed files with 82 additions and 45 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: search.h,v 1.20 2013/04/27 21:35:25 joerg Exp $ */
/* $NetBSD: search.h,v 1.21 2014/07/20 13:34:17 christos Exp $ */
/*
* Written by J.T. Conklin <jtc@NetBSD.org>
@ -62,8 +62,12 @@ void hdestroy(void);
ENTRY *hsearch(ENTRY, ACTION);
#ifdef _NETBSD_SOURCE
#define FREE_KEY 1
#define FREE_DATA 2
void hdestroy1(int);
int hcreate_r(size_t, struct hsearch_data *);
void hdestroy_r(struct hsearch_data *);
void hdestroy1_r(struct hsearch_data *, int);
int hsearch_r(ENTRY, ACTION, ENTRY **, struct hsearch_data *);
#endif /* _NETBSD_SOURCE */

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile.inc,v 1.81 2014/01/08 02:15:42 christos Exp $
# $NetBSD: Makefile.inc,v 1.82 2014/07/20 13:34:17 christos Exp $
# from: @(#)Makefile.inc 8.3 (Berkeley) 2/4/95
# stdlib sources
@ -66,6 +66,7 @@ MLINKS+=getenv.3 setenv.3 getenv.3 unsetenv.3 getenv.3 putenv.3
MLINKS+=getenv.3 getenv_r.3
MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
MLINKS+=hcreate.3 hcreate_r.3 hcreate.3 hdestroy_r.3 hcreate.3 hsearch_r.3
MLINKS+=hcreate.3 hdestroy1.3 hcreate.3 hdestroy1_r.3
MLINKS+=insque.3 remque.3
MLINKS+=lsearch.3 lfind.3
MLINKS+=malloc.3 calloc.3 malloc.3 realloc.3 malloc.3 free.3

View File

@ -1,4 +1,4 @@
.\" $NetBSD: hcreate.3,v 1.10 2011/09/15 09:14:54 wiz Exp $
.\" $NetBSD: hcreate.3,v 1.11 2014/07/20 13:34:17 christos Exp $
.\"
.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -27,14 +27,16 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 14, 2011
.Dd July 20, 2014
.Dt HCREATE 3
.Os
.Sh NAME
.Nm hcreate ,
.Nm hcreate_r ,
.Nm hdestroy ,
.Nm hdestroy1 ,
.Nm hdestroy_r ,
.Nm hdestroy1_r ,
.Nm hsearch ,
.Nm hsearch_r
.Nd manage hash search table
@ -49,7 +51,11 @@
.Ft void
.Fn hdestroy "void"
.Ft void
.Fn hdestroy1 "int flags"
.Ft void
.Fn hdestroy_r "struct hsearch_data *table"
.Ft void
.Fn hdestroy1_r "struct hsearch_data *table" "int flags"
.Ft ENTRY *
.Fn hsearch "ENTRY item" "ACTION action"
.Ft int
@ -60,6 +66,8 @@ The
.Fn hcreate_r ,
.Fn hdestroy ,
.Fn hdestroy_r
.Fn hdestroy1 ,
.Fn hdestroy1_r
.Fn hsearch ,
and
.Fn hsearch_r
@ -141,33 +149,49 @@ Search the hash table without inserting
.Fa item .
.El
.Pp
Note that the comparison
.Fa key
must be allocated using
.Xr malloc 3
or
.Xr calloc 3
if action is
.Dv ENTER
The traditional
.Fn hdestroy
and
.Fn hdestroy
will be called.
This is because
.Fn hdestroy
will call
.Fn hdestroy_r
functions don't
.Xr free 3
for each comparison
the data associated with the
.Fa key
(but not
.Fa data ) .
Typically the comparison
and
.Fa value
of each entry, because they did not allocate them.
Since there is no
.Dq iterator
function provided, the
.Fn hdestroy1
and
.Fn hdestroy1_r
allow controlling if the
.Fa key
is allocated by using
.Xr strdup 3 .
or
.Fa value
will be freed using the
.Fa flags
argument.
If the bit
.Dv FREE_KEY
is set, then the
.Fa key
of each entry will be
passed to
.Xr free 3 .
If the bit
.Dv FREE_VALUE
is set, then the
.Fa value
of each entry will be
passed to
.Xr free 3 .
.Pp
The
.Fn hcreate_r ,
.Fn hdestroy_r ,
.Fn hdestroy1_r ,
and
.Fn hsearch_r
functions are re-entrant versions of the above functions that can
@ -266,6 +290,7 @@ given is not found.
.Xr bsearch 3 ,
.Xr lsearch 3 ,
.Xr malloc 3 ,
.Xr free 3 ,
.Xr strcmp 3
.Sh STANDARDS
The
@ -291,6 +316,13 @@ and
functions are
.Tn GNU
extensions.
The
.Fn hdestroy1
and
.Fn hdestroy1_r
are
.Nx
extensions.
.Sh CAVEATS
At least the following limitations can be mentioned:
.Bl -bullet
@ -301,20 +333,5 @@ interface permits the use of only one hash table at a time.
.It
Individual hash table entries can be added, but not deleted.
.It
The standard is indecipherable about the
internal memory usage of the functions,
mentioning only that
.Do
.Fn hcreate
and
.Fn hsearch
functions may use
.Fn malloc
to allocate space
.Dc .
This limits the portability of the functions,
given that other implementations may not
.Xr free 3
the buffer pointed by
.Fa key .
There is no iterator to scan for all entries in the table.
.El

View File

@ -1,4 +1,4 @@
/* $NetBSD: hcreate.c,v 1.8 2011/09/17 16:54:39 christos Exp $ */
/* $NetBSD: hcreate.c,v 1.9 2014/07/20 13:34:17 christos Exp $ */
/*
* Copyright (c) 2001 Christopher G. Demetriou
@ -43,7 +43,7 @@
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: hcreate.c,v 1.8 2011/09/17 16:54:39 christos Exp $");
__RCSID("$NetBSD: hcreate.c,v 1.9 2014/07/20 13:34:17 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#if !defined(lint)
@ -141,14 +141,20 @@ hcreate_r(size_t nel, struct hsearch_data *head)
}
void
hdestroy(void)
hdestroy1(int flags)
{
_DIAGASSERT(htable.table != NULL);
hdestroy_r(&htable);
hdestroy1_r(&htable, flags);
}
void
hdestroy_r(struct hsearch_data *head)
hdestroy(void)
{
hdestroy1(0);
}
void
hdestroy1_r(struct hsearch_data *head, int flags)
{
struct internal_entry *ie;
size_t idx;
@ -166,13 +172,22 @@ hdestroy_r(struct hsearch_data *head)
while (!SLIST_EMPTY(&table[idx])) {
ie = SLIST_FIRST(&table[idx]);
SLIST_REMOVE_HEAD(&table[idx], link);
free(ie->ent.key);
if (flags & FREE_KEY)
free(ie->ent.key);
if (flags & FREE_DATA)
free(ie->ent.data);
free(ie);
}
}
free(table);
}
void
hdestroy_r(struct hsearch_data *head)
{
hdestroy1_r(head, 0);
}
ENTRY *
hsearch(ENTRY item, ACTION action)
{