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 { typedef struct _pr {
struct _pr *nextpr; /* next print unit */ struct _pr *nextpr; /* next print unit */
unsigned int flags; /* flag values */ unsigned flags; /* flag values */
int bcnt; /* byte count */ int bcnt; /* byte count */
char *cchar; /* conversion character */ char *cchar; /* conversion character */
char *fmt; /* printf format */ char *fmt; /* printf format */
@ -32,7 +32,7 @@ typedef struct _pr {
typedef struct _fu { typedef struct _fu {
struct _fu *nextfu; /* next format unit */ struct _fu *nextfu; /* next format unit */
struct _pr *nextpr; /* next print unit */ struct _pr *nextpr; /* next print unit */
unsigned int flags; /* flag values */ unsigned flags; /* flag values */
int reps; /* repetition count */ int reps; /* repetition count */
int bcnt; /* byte count */ int bcnt; /* byte count */
char *fmt; /* format string */ 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_dump(char **argv) FAST_FUNC;
extern int bb_dump_size(FS * fs) FAST_FUNC; extern int bb_dump_size(FS * fs) FAST_FUNC;
extern FS *bb_dump_fshead; /* head of format strings */ extern FS *bb_dump_fshead; /* head of format strings */
extern int bb_dump_blocksize; /* data block size */ extern int bb_dump_blocksize; /* data block size */
extern int bb_dump_length; /* max bytes to read */ extern int bb_dump_length; /* max bytes to read */
extern enum _vflag bb_dump_vflag; extern smallint /*enum _vflag*/ bb_dump_vflag;
extern off_t bb_dump_skip; /* bytes to skip */ extern off_t bb_dump_skip; /* bytes to skip */
#if __GNUC_PREREQ(4,1) #if __GNUC_PREREQ(4,1)
# pragma GCC visibility pop # pragma GCC visibility pop

View File

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