vcscanf: refactor buffer usage

Create a dedicated buffer for floating point parsing purposes
and restore the original string decoding buffer just as it was.
This fixes the segmentation fault in the tinylinux mode tests.
I suspect the floating point buffer was ending up in the free list
somehow which resulted in a double free when the function exited.
This commit is contained in:
Matheus Afonso Martins Moreira 2023-11-12 23:01:14 -03:00
parent 8f12a061ad
commit 850ab95369

View file

@ -35,17 +35,17 @@
c; \ c; \
}) })
#define BUFFER_GROW 48 #define FP_BUFFER_GROW 48
#define BUFFER \ #define BUFFER \
({ \ ({ \
int c = READ; \ int c = READ; \
if (bufcur >= bufsize - 1) { \ if (fpbufcur >= fpbufsize - 1) { \
bufsize = bufsize + BUFFER_GROW; \ fpbufsize = fpbufsize + FP_BUFFER_GROW; \
buf = realloc(buf, bufsize); \ fpbuf = realloc(fpbuf, fpbufsize); \
} \ } \
if (c != -1) { \ if (c != -1) { \
buf[bufcur++] = c; \ fpbuf[fpbufcur++] = c; \
buf[bufcur] = '\0'; \ fpbuf[fpbufcur] = '\0'; \
} \ } \
c; \ c; \
}) })
@ -76,9 +76,9 @@ int __vcscanf(int callback(void *), //
struct FreeMe *next; struct FreeMe *next;
void *ptr; void *ptr;
} *freeme = NULL; } *freeme = NULL;
unsigned char *buf = NULL; unsigned char *fpbuf = NULL;
size_t bufsize; size_t fpbufsize;
size_t bufcur; size_t fpbufcur;
const unsigned char *p = (const unsigned char *)fmt; const unsigned char *p = (const unsigned char *)fmt;
int *n_ptr; int *n_ptr;
int items = 0; int items = 0;
@ -103,6 +103,8 @@ int __vcscanf(int callback(void *), //
break; break;
case '%': { case '%': {
uint128_t number; uint128_t number;
unsigned char *buf;
size_t bufsize;
double fp; double fp;
unsigned width = 0; unsigned width = 0;
unsigned char bits = 32; unsigned char bits = 32;
@ -241,11 +243,11 @@ int __vcscanf(int callback(void *), //
while (isspace(c)) { while (isspace(c)) {
c = READ; c = READ;
} }
bufsize = BUFFER_GROW; fpbufsize = FP_BUFFER_GROW;
buf = malloc(bufsize); fpbuf = malloc(fpbufsize);
bufcur = 0; fpbufcur = 0;
buf[bufcur++] = c; fpbuf[fpbufcur++] = c;
buf[bufcur] = '\0'; fpbuf[fpbufcur] = '\0';
goto ConsumeFloatingPointNumber; goto ConsumeFloatingPointNumber;
default: default:
items = einval(); items = einval();
@ -466,7 +468,7 @@ int __vcscanf(int callback(void *), //
break; break;
} while ((c = BUFFER) != -1); } while ((c = BUFFER) != -1);
GotFloatingPointNumber: GotFloatingPointNumber:
fp = strtod((char *)buf, NULL); fp = strtod((char *)fpbuf, NULL);
if (!discard) { if (!discard) {
++items; ++items;
void *out = va_arg(va, void *); void *out = va_arg(va, void *);
@ -476,9 +478,9 @@ int __vcscanf(int callback(void *), //
*(double *)out = (double)fp; *(double *)out = (double)fp;
} }
} }
free(buf); free(fpbuf);
buf = NULL; fpbuf = NULL;
bufcur = bufsize = 0; fpbufcur = fpbufsize = 0;
continue; continue;
ReportConsumed: ReportConsumed:
n_ptr = va_arg(va, int *); n_ptr = va_arg(va, int *);
@ -565,6 +567,6 @@ Done:
if (items == -1) free(entry->ptr); if (items == -1) free(entry->ptr);
free(entry); free(entry);
} }
if (buf) free(buf); if (fpbuf) free(fpbuf);
return items; return items;
} }