od,hexdump: fix bug where xrealloc may move pointer,

leaving other pointers dangling (bug 4104).
 + many style fixes in libbb/dump.c.
This commit is contained in:
Denis Vlasenko 2008-07-16 07:22:14 +00:00
parent 018bee6afb
commit bd9874db74
2 changed files with 75 additions and 69 deletions

View File

@ -22,7 +22,7 @@ enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */
typedef struct _pr {
struct _pr *nextpr; /* next print unit */
unsigned int flags; /* flag values */
unsigned flags; /* flag values */
int bcnt; /* byte count */
char *cchar; /* conversion character */
char *fmt; /* printf format */
@ -32,7 +32,7 @@ typedef struct _pr {
typedef struct _fu {
struct _fu *nextfu; /* next format unit */
struct _pr *nextpr; /* next print unit */
unsigned int flags; /* flag values */
unsigned flags; /* flag values */
int reps; /* repetition count */
int bcnt; /* byte count */
char *fmt; /* format string */
@ -48,11 +48,11 @@ extern void bb_dump_add(const char *fmt) FAST_FUNC;
extern int bb_dump_dump(char **argv) FAST_FUNC;
extern int bb_dump_size(FS * fs) FAST_FUNC;
extern FS *bb_dump_fshead; /* head of format strings */
extern int bb_dump_blocksize; /* data block size */
extern int bb_dump_length; /* max bytes to read */
extern enum _vflag bb_dump_vflag;
extern off_t bb_dump_skip; /* bytes to skip */
extern FS *bb_dump_fshead; /* head of format strings */
extern int bb_dump_blocksize; /* data block size */
extern int bb_dump_length; /* max bytes to read */
extern smallint /*enum _vflag*/ bb_dump_vflag;
extern off_t bb_dump_skip; /* bytes to skip */
#if __GNUC_PREREQ(4,1)
# pragma GCC visibility pop

View File

@ -14,17 +14,18 @@
#include "libbb.h"
#include "dump.h"
enum _vflag bb_dump_vflag = FIRST;
FS *bb_dump_fshead; /* head of format strings */
FS *bb_dump_fshead; /* head of format strings */
off_t bb_dump_skip; /* bytes to skip */
int bb_dump_blocksize; /* data block size */
int bb_dump_length = -1; /* max bytes to read */
smallint /*enum _vflag*/ bb_dump_vflag = FIRST;
static FU *endfu;
static char **_argv;
static off_t savaddress; /* saved address/offset in stream */
static off_t eaddress; /* end address */
static off_t address; /* address/offset in stream */
off_t bb_dump_skip; /* bytes to skip */
static int exitval; /* final exit value */
int bb_dump_blocksize; /* data block size */
int bb_dump_length = -1; /* max bytes to read */
static off_t savaddress; /* saved address/offset in stream */
static off_t eaddress; /* end address */
static off_t address; /* address/offset in stream */
static int exitval; /* final exit value */
static const char index_str[] ALIGN1 = ".#-+ 0123456789";
@ -78,7 +79,7 @@ int FAST_FUNC bb_dump_size(FS *fs)
return cur_size;
}
static void rewrite(FS * fs)
static void rewrite(FS *fs)
{
enum { NOTOKAY, USEBCNT, USEPREC } sokay;
PR *pr, **nextpr = NULL;
@ -104,7 +105,8 @@ static void rewrite(FS * fs)
*/
/* bb_dump_skip preceding text and up to the next % sign */
for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
for (p1 = fmtp; *p1 && *p1 != '%'; ++p1)
continue;
/* only text in the string */
if (!*p1) {
@ -120,14 +122,17 @@ static void rewrite(FS * fs)
if (fu->bcnt) {
sokay = USEBCNT;
/* bb_dump_skip to conversion character */
for (++p1; strchr(index_str, *p1); ++p1);
for (++p1; strchr(index_str, *p1); ++p1)
continue;
} else {
/* bb_dump_skip any special chars, field width */
while (strchr(index_str + 1, *++p1));
while (strchr(index_str + 1, *++p1))
continue;
if (*p1 == '.' && isdigit(*++p1)) {
sokay = USEPREC;
prec = atoi(p1);
while (isdigit(*++p1));
while (isdigit(*++p1))
continue;
} else
sokay = NOTOKAY;
}
@ -139,12 +144,11 @@ static void rewrite(FS * fs)
* rewrite the format as necessary, set up blank-
* pbb_dump_adding for end of data.
*/
if (*p1 == 'c') {
pr->flags = F_CHAR;
DO_BYTE_COUNT_1:
DO_BYTE_COUNT_1:
byte_count_str = "\001";
DO_BYTE_COUNT:
DO_BYTE_COUNT:
if (fu->bcnt) {
do {
if (fu->bcnt == *byte_count_str) {
@ -160,7 +164,7 @@ static void rewrite(FS * fs)
} else if (*p1 == 'l') {
++p2;
++p1;
DO_INT_CONV:
DO_INT_CONV:
{
const char *e;
e = strchr(lcc, *p1);
@ -221,7 +225,7 @@ static void rewrite(FS * fs)
goto DO_BAD_CONV_CHAR;
}
} else {
DO_BAD_CONV_CHAR:
DO_BAD_CONV_CHAR:
bb_error_msg_and_die("bad conversion character %%%s", p1);
}
@ -233,16 +237,17 @@ static void rewrite(FS * fs)
p1[1] = '\0';
pr->fmt = xstrdup(fmtp);
*p2 = savech;
pr->cchar = pr->fmt + (p1 - fmtp);
//Too early! xrealloc can move pr->fmt!
//pr->cchar = pr->fmt + (p1 - fmtp);
/* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
* Skip subsequent text and up to the next % sign and tack the
* additional text onto fmt: eg. if fmt is "%x is a HEX number",
* we lose the " is a HEX number" part of fmt.
*/
for (p3 = p2; *p3 && *p3 != '%'; p3++);
if (p3 > p2)
{
for (p3 = p2; *p3 && *p3 != '%'; p3++)
continue;
if (p3 > p2) {
savech = *p3;
*p3 = '\0';
pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1);
@ -251,6 +256,7 @@ static void rewrite(FS * fs)
p2 = p3;
}
pr->cchar = pr->fmt + (p1 - fmtp);
fmtp = p2;
/* only one conversion character if byte count */
@ -276,9 +282,11 @@ static void rewrite(FS * fs)
* gets output from the last iteration of the format unit.
*/
for (fu = fs->nextfu;; fu = fu->nextfu) {
if (!fu->nextfu && fs->bcnt < bb_dump_blocksize &&
!(fu->flags & F_SETREP) && fu->bcnt)
if (!fu->nextfu && fs->bcnt < bb_dump_blocksize
&& !(fu->flags & F_SETREP) && fu->bcnt
) {
fu->reps += (bb_dump_blocksize - fs->bcnt) / fu->bcnt;
}
if (fu->reps > 1) {
for (pr = fu->nextpr;; pr = pr->nextpr)
if (!pr->nextpr)
@ -377,7 +385,7 @@ static unsigned char *get(void)
* and no other files are available, zero-pad the rest of the
* block and set the end flag.
*/
if (!bb_dump_length || (ateof && !next((char **) NULL))) {
if (!bb_dump_length || (ateof && !next(NULL))) {
if (need == bb_dump_blocksize) {
return NULL;
}
@ -387,12 +395,12 @@ static unsigned char *get(void)
}
return NULL;
}
memset((char *) curp + nread, 0, need);
memset(curp + nread, 0, need);
eaddress = address + nread;
return curp;
}
n = fread((char *) curp + nread, sizeof(unsigned char),
bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
n = fread(curp + nread, sizeof(unsigned char),
bb_dump_length == -1 ? need : MIN(bb_dump_length, need), stdin);
if (!n) {
if (ferror(stdin)) {
bb_simple_perror_msg(_argv[-1]);
@ -407,7 +415,8 @@ static unsigned char *get(void)
need -= n;
if (!need) {
if (bb_dump_vflag == ALL || bb_dump_vflag == FIRST
|| memcmp(curp, savp, bb_dump_blocksize)) {
|| memcmp(curp, savp, bb_dump_blocksize)
) {
if (bb_dump_vflag == DUP || bb_dump_vflag == FIRST) {
bb_dump_vflag = WAIT;
}
@ -426,7 +435,7 @@ static unsigned char *get(void)
}
}
static void bpad(PR * pr)
static void bpad(PR *pr)
{
char *p1, *p2;
@ -436,10 +445,13 @@ static void bpad(PR * pr)
*/
pr->flags = F_BPAD;
*pr->cchar = 's';
for (p1 = pr->fmt; *p1 != '%'; ++p1);
for (p1 = pr->fmt; *p1 != '%'; ++p1)
continue;
for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
if (pr->nospace) pr->nospace--;
while ((*p2++ = *p1++) != 0);
if (pr->nospace)
pr->nospace--;
while ((*p2++ = *p1++) != 0)
continue;
}
static const char conv_str[] ALIGN1 =
@ -454,7 +466,7 @@ static const char conv_str[] ALIGN1 =
;
static void conv_c(PR * pr, unsigned char * p)
static void conv_c(PR *pr, unsigned char *p)
{
const char *str = conv_str;
char buf[10];
@ -469,7 +481,7 @@ static void conv_c(PR * pr, unsigned char * p)
if (isprint(*p)) {
*pr->cchar = 'c';
(void) printf(pr->fmt, *p);
printf(pr->fmt, *p);
} else {
sprintf(buf, "%03o", (int) *p);
str = buf;
@ -479,7 +491,7 @@ static void conv_c(PR * pr, unsigned char * p)
}
}
static void conv_u(PR * pr, unsigned char * p)
static void conv_u(PR *pr, unsigned char *p)
{
static const char list[] ALIGN1 =
"nul\0soh\0stx\0etx\0eot\0enq\0ack\0bel\0"
@ -511,7 +523,6 @@ static void display(void)
PR *pr;
int cnt;
unsigned char *bp;
off_t saveaddress;
unsigned char savech = 0, *savebp;
@ -536,7 +547,7 @@ static void display(void)
/* PRINT; */
switch (pr->flags) {
case F_ADDRESS:
printf(pr->fmt, (unsigned int) address);
printf(pr->fmt, (unsigned) address);
break;
case F_BPAD:
printf(pr->fmt, "");
@ -553,13 +564,11 @@ static void display(void)
switch (pr->bcnt) {
case 4:
memmove((char *) &fval, (char *) bp,
sizeof(fval));
memmove(&fval, bp, sizeof(fval));
printf(pr->fmt, fval);
break;
case 8:
memmove((char *) &dval, (char *) bp,
sizeof(dval));
memmove(&dval, bp, sizeof(dval));
printf(pr->fmt, dval);
break;
}
@ -574,13 +583,11 @@ static void display(void)
printf(pr->fmt, (int) *bp);
break;
case 2:
memmove((char *) &sval, (char *) bp,
sizeof(sval));
memmove(&sval, bp, sizeof(sval));
printf(pr->fmt, (int) sval);
break;
case 4:
memmove((char *) &ival, (char *) bp,
sizeof(ival));
memmove(&ival, bp, sizeof(ival));
printf(pr->fmt, ival);
break;
}
@ -599,21 +606,19 @@ static void display(void)
conv_u(pr, bp);
break;
case F_UINT:{
unsigned int ival;
unsigned ival;
unsigned short sval;
switch (pr->bcnt) {
case 1:
printf(pr->fmt, (unsigned int) * bp);
printf(pr->fmt, (unsigned) *bp);
break;
case 2:
memmove((char *) &sval, (char *) bp,
sizeof(sval));
printf(pr->fmt, (unsigned int) sval);
memmove(&sval, bp, sizeof(sval));
printf(pr->fmt, (unsigned) sval);
break;
case 4:
memmove((char *) &ival, (char *) bp,
sizeof(ival));
memmove(&ival, bp, sizeof(ival));
printf(pr->fmt, ival);
break;
}
@ -642,10 +647,10 @@ static void display(void)
for (pr = endfu->nextpr; pr; pr = pr->nextpr) {
switch (pr->flags) {
case F_ADDRESS:
(void) printf(pr->fmt, (unsigned int) eaddress);
printf(pr->fmt, (unsigned) eaddress);
break;
case F_TEXT:
(void) printf(pr->fmt);
printf(pr->fmt);
break;
}
}
@ -676,10 +681,11 @@ int FAST_FUNC bb_dump_dump(char **argv)
void FAST_FUNC bb_dump_add(const char *fmt)
{
static FS **nextfs;
const char *p;
char *p1;
char *p2;
static FS **nextfs;
FS *tfs;
FU *tfu, **nextfu;
const char *savep;
@ -712,7 +718,8 @@ void FAST_FUNC bb_dump_add(const char *fmt)
/* if leading digit, repetition count */
if (isdigit(*p)) {
for (savep = p; isdigit(*p); ++p);
for (savep = p; isdigit(*p); ++p)
continue;
if (!isspace(*p) && *p != '/') {
bb_error_msg_and_die("bad format {%s}", fmt);
}
@ -732,7 +739,8 @@ void FAST_FUNC bb_dump_add(const char *fmt)
if (isdigit(*p)) {
// TODO: use bb_strtou
savep = p;
do p++; while (isdigit(*p));
while (isdigit(*++p))
continue;
if (!isspace(*p)) {
bb_error_msg_and_die("bad format {%s}", fmt);
}
@ -750,9 +758,7 @@ void FAST_FUNC bb_dump_add(const char *fmt)
bb_error_msg_and_die("bad format {%s}", fmt);
}
}
tfu->fmt = xmalloc(p - savep + 1);
strncpy(tfu->fmt, savep, p - savep);
tfu->fmt[p - savep] = '\0';
tfu->fmt = xstrndup(savep, p - savep);
/* escape(tfu->fmt); */
p1 = tfu->fmt;