PR/10266: Jason R. Thorpe: curses programs totally broken.

Re-write t_agetstr() so that it does not use realloc so userland
programs don't break. We now use an internal buffer to keep track
of the memory we allocate. This changes the api of t_agetstr() to
take 2 fewer arguments, but there are not many programs that use it.
Please note that this does not change binary compatibility with the
previous t_agetstr() since the usage was:

	char *area, *p;

	*area = NULL;
	t_agetstr(ti, "ic", &area, &p);
	...
	free(area);

Since we don't touch the arguments and free(NULL) is a no-op, nothing
breaks.

Since we don't break binary compatibility there is no reason to bump
the library's major number, but since we change t_agetstr() I'll bump
the minor number for good measure.
This commit is contained in:
christos 2001-11-02 18:24:20 +00:00
parent 0812154e48
commit a6265aca19
4 changed files with 52 additions and 80 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: termcap.3,v 1.21 2001/01/05 23:05:08 christos Exp $
.\" $NetBSD: termcap.3,v 1.22 2001/11/02 18:24:20 christos Exp $
.\"
.\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -74,7 +74,7 @@
.Ft char *
.Fn t_getstr "struct tinfo *info" "char *id" "char **area" "size_t *limit"
.Ft char *
.Fn t_agetstr "struct tinfo *info" "char *id" "char **buffer" "char **area"
.Fn t_agetstr "struct tinfo *info" "char *id"
.Ft int
.Fn t_getterm "struct tinfo *info" "char **area" "size_t *limit"
.Ft int
@ -342,55 +342,11 @@ The function
.Fn t_agetstr
performs the same function as
.Fn t_getstr
except sufficient memory is first allocated to hold the desired string
argument before adding it to the buffer. To initialise the buffer for
except it handles memory allocation automatically. The memory that
.Fn t_agetstr
the first call must be done with the contents of
.Fa buffer
set to NULL. Subsequent calls to
.Fn t_agetstr
can pass
.Fa buffer
and
.Fa area
in unmodified and the requested string argument will be appended to
the buffer after sufficient memory has been allocated. Modifying either
.Fa buffer
or
.Fa area
between calls to
.Fn t_agetstr
will certainly lead to the function misbehaving. When the storage
allocated by
.Fn t_agetstr
is no longer required it can be freed by passing the pointer contained
in
.Fa buffer
to
.Fn free .
If an error occurs within
.Fn t_agetstr
a NULL will be returned and
.Fa buffer
and
.Fa area
will remain unmodified.
.Em NOTE
.Fn t_agetstr
uses
.Fn realloc
to reallocate the buffer memory so saving a copy of either
.Fa buffer
or
.Fa area
for use after subsequent calls to
.Fn t_agetstr
is likely to fail. It is best to keep offsets from
.Fa buffer
to the desired string and calculate pointer addresses only after all
the calls to
.Fn t_agetstr
have been done.
allocates will be freed when
.Fn t_freent
is called.
.Pp
The function
.Fn t_getterm

View File

@ -1,4 +1,4 @@
/* $NetBSD: termcap.c,v 1.39 2001/10/31 21:52:17 christos Exp $ */
/* $NetBSD: termcap.c,v 1.40 2001/11/02 18:24:20 christos Exp $ */
/*
* Copyright (c) 1980, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)termcap.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: termcap.c,v 1.39 2001/10/31 21:52:17 christos Exp $");
__RCSID("$NetBSD: termcap.c,v 1.40 2001/11/02 18:24:20 christos Exp $");
#endif
#endif /* not lint */
@ -108,6 +108,7 @@ t_setinfo(struct tinfo **bp, const char *entry)
(*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit);
if ((*bp)->bc)
(*bp)->bc = strdup((*bp)->bc);
(*bp)->tbuf = NULL;
return 0;
}
@ -251,6 +252,7 @@ t_getent(bp, name)
(*bp)->bc = t_getstr(*bp, "bc", &cap_ptr, &limit);
if ((*bp)->bc)
(*bp)->bc = strdup((*bp)->bc);
(*bp)->tbuf = NULL;
}
return (i + 1);
@ -460,39 +462,44 @@ tgetstr(id, area)
* fix it for now is to allocate a lot -- 8K, and leak if we need to
* realloc. This API needs to be destroyed!.
*/
#define BSIZE 8192
#define BSIZE 256
char *
t_agetstr(struct tinfo *info, const char *id, char **bufptr, char **area)
t_agetstr(struct tinfo *info, const char *id)
{
size_t new_size;
char *new_buf;
struct tbuf *tb;
_DIAGASSERT(info != NULL);
_DIAGASSERT(id != NULL);
_DIAGASSERT(bufptr != NULL);
_DIAGASSERT(area != NULL);
t_getstr(info, id, NULL, &new_size);
/* either the string is empty or the capability does not exist. */
if (new_size == 0 || new_size > BSIZE)
if (new_size == 0)
return NULL;
/* check if we have a buffer, if not malloc one and fill it in. */
if (*bufptr == NULL) {
if ((new_buf = (char *) malloc(BSIZE)) == NULL)
if ((tb = info->tbuf) == NULL || (tb->eptr - tb->ptr) < new_size) {
if (new_size < BSIZE)
new_size = BSIZE;
else
new_size++;
if ((tb = malloc(sizeof(*info->tbuf))) == NULL)
return NULL;
*bufptr = new_buf;
*area = new_buf;
} else if (*area - *bufptr >= BSIZE - new_size) {
char buf[BSIZE];
char *b = buf;
size_t len = BSIZE;
/* Leak! */
return strdup(t_getstr(info, id, &b, &len));
if ((tb->data = tb->ptr = tb->eptr = malloc(new_size)) == NULL)
return NULL;
tb->eptr += new_size;
if (info->tbuf != NULL)
tb->next = info->tbuf;
else
tb->next = NULL;
info->tbuf = tb;
}
return t_getstr(info, id, area, NULL);
return t_getstr(info, id, &tb->ptr, NULL);
}
/*
@ -503,12 +510,18 @@ void
t_freent(info)
struct tinfo *info;
{
struct tbuf *tb;
_DIAGASSERT(info != NULL);
free(info->info);
if (info->up != NULL)
free(info->up);
if (info->bc != NULL)
free(info->bc);
for (tb = info->tbuf; tb;) {
tb = info->tbuf->next;
free(info->tbuf->data);
free(info->tbuf);
}
free(info);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: termcap.h,v 1.12 2000/05/28 09:58:15 blymn Exp $ */
/* $NetBSD: termcap.h,v 1.13 2001/11/02 18:24:20 christos Exp $ */
/*-
* Copyright (c) 1992, 1993
@ -60,7 +60,7 @@ int t_getent __P((struct tinfo **, const char *));
int t_getnum __P((struct tinfo *, const char *));
int t_getflag __P((struct tinfo *, const char *));
char *t_getstr __P((struct tinfo *, const char *, char **, size_t *));
char *t_agetstr(struct tinfo *, const char *, char **, char **);
char *t_agetstr(struct tinfo *, const char *);
int t_getterm(struct tinfo *, char **, size_t *);
int t_goto __P((struct tinfo *, const char *, int, int, char *, size_t));
int t_puts __P((struct tinfo *, const char *, int,

View File

@ -1,4 +1,4 @@
/* $NetBSD: termcap_private.h,v 1.3 2001/06/13 10:46:00 wiz Exp $ */
/* $NetBSD: termcap_private.h,v 1.4 2001/11/02 18:24:20 christos Exp $ */
/*-
* Copyright (c) 1998-1999 Brett Lymn
@ -37,7 +37,10 @@ struct tinfo
char *info;
char *up; /* for use by tgoto */
char *bc; /* for use by tgoto */
struct tbuf { /* for use by t_agetstr() */
struct tbuf *next; /* pointer to next area */
char *data; /* pointer to beginning of buffer */
char *ptr; /* current data pointer */
char *eptr; /* pointer to the end of buffer */
} *tbuf;
};