[Cbe-oss-dev] [PATCH] libspe2: Fix format parsers in printf/scanf callback handlers
Kazunori Asayama
asayama at sm.sony.co.jp
Fri Aug 24 21:26:43 EST 2007
This patch fixes following problems regarding format parsers in
printf/scanf callback handlers.
- scanf fails to parse a format if any of an 'h' modifier or an '*'
flag is specified.
- scanf fails to parse a format if both of precision and length
modifier are specified.
- scanf can fail to parse a format if scan-set (%[...]) contains a
left bracket ([) or a circumflex (^) as a member of scan-list.
- scanf returns an incorrect value for an 'n' specifier with an 'l'
modifier on 64-bit environment.
- missing format specifiers and modifiers defined in the C99 spec.
- clean up.
OK to apply ?
Signed-off-by: Kazunori Asayama <asayama at sm.sony.co.jp>
---
spebase/default_c99_handler.c | 311 +++++++++++++++++++++---------------------
1 file changed, 159 insertions(+), 152 deletions(-)
Index: b/spebase/default_c99_handler.c
===================================================================
--- a/spebase/default_c99_handler.c 2007-08-24 11:21:52.000000000 +0900
+++ b/spebase/default_c99_handler.c 2007-08-24 20:08:25.000000000 +0900
@@ -67,11 +67,6 @@
* The C99 handlers use direct-mapped access to LS in order to fetch parameters
* from the stack frame, and to place return values (including errno) into the
* expected locations.
- *
- * Known Errata:
- * 1. The C99 handlers are currently written assuming a 32b PPC-ABI.
- * A small ammount of work will be necessary to make the vargs
- * handlers functional in 64b PPC-ABI.
*/
#define SPE_C99_OP_SHIFT 24
@@ -179,7 +174,6 @@ typedef unsigned long long __va_elem;
(((unsigned long) (_vargs) + __OFFSET(_type)) & __MASK(_type))
/* Put a value into the va_list pointed to by '_vargs'.
- * TO-DO: update this to support 64b PPC-ABI, if needed.
*/
#define __VA_LIST_PUT(_vargs, _type, _a) \
_vargs = (__va_elem *) __VA_LIST_ALIGN_TO_TYPE(_vargs, _type); \
@@ -229,7 +223,6 @@ struct __va_temp {
int *ptr;
};
-/* TO-DO: update these to support 64b PPC-ABI. */
static int __do_vfprintf(FILE * stream, char *format, __va_elem * vlist)
{
#if !defined(__powerpc64__)
@@ -422,6 +415,35 @@ static inline FILE *get_FILE(int nr)
} while (!done); \
}
+#define SKIP_LENGTH_MODIFIERS(p, h, l) { \
+ int done = 0; \
+ h = 0; l = 0; \
+ do { \
+ switch (*p) { \
+ case 'h': \
+ h++; \
+ p++; \
+ break; \
+ case 'l': \
+ l++; \
+ p++; \
+ break; \
+ case 'j': \
+ l = 2; \
+ p++; \
+ break; \
+ case 'z': \
+ case 't': \
+ l = 1; \
+ p++; \
+ break; \
+ default: \
+ done = 1; \
+ break; \
+ } \
+ } while (!done); \
+}
+
#define COUNT_FIELD_WIDTH(p, output) { \
switch (*p) { \
case '0': \
@@ -470,21 +492,15 @@ static inline FILE *get_FILE(int nr)
} \
}
-#define SKIP_SCANF_FLAG_CHARS(p, h, l, sp) { \
+#define SKIP_SCANF_FLAG_CHARS(p, sp) { \
int done = 0; \
- h = 0; l = 0; sp = 0; \
+ sp = 0; \
do { \
switch (*p) { \
- case 'h': \
- h = 1; \
- p++; \
- case 'l': \
- l++; \
- p++; \
- break; \
case '*': \
sp = 1; \
p++; \
+ break; \
default: \
done = 1; \
break; \
@@ -494,15 +510,14 @@ static inline FILE *get_FILE(int nr)
#define SKIP_CHAR_SET(p) \
{ \
- char _prev; \
- do { \
- p = strchr(p, ']'); \
- if (p == NULL) { \
- DEBUG_PRINTF("SKIP_CHAR_SET() error."); \
- return 1; \
- } \
- _prev = *((p)-1); \
- } while ((_prev == '[') || (_prev == '^')); \
+ p++; \
+ if (*p == '^') p++; \
+ if (*p == ']') p++; \
+ p = strchr(p, ']'); \
+ if (p == NULL) { \
+ DEBUG_PRINTF("SKIP_CHAR_SET() error."); \
+ return 1; \
+ } \
}
static int __nr_format_args(const char *format)
@@ -527,36 +542,63 @@ static int __nr_format_args(const char *
static int __parse_printf_format(char *ls, char *format,
struct spe_va_list *spe_vlist,
- __va_elem * vlist, int nr_vargs)
+ __va_elem * vlist, struct __va_temp *vtemps, int nr_vargs)
{
int fw, pr;
+ int format_half, format_long;
int ival;
double dval;
long long llval;
unsigned int ls_offset;
char *p;
- char *str;
-
- if (nr_vargs == 0)
- return 0;
+ void *ptr;
- for (p = (char *) format; *p; p++) {
+ for (p = format; nr_vargs > 0 && *p; p++) {
p = strchr(p, '%');
if (!p) {
/* Done with formatting. */
break;
}
p++;
+ nr_vargs--;
SKIP_PRINTF_FLAG_CHARS(p);
SKIP_FIELD_WIDTH(p, fw, 1);
SKIP_PRECISION(p, pr);
+ SKIP_LENGTH_MODIFIERS(p, format_half, format_long);
switch (*p) {
- case 'c':
case 'd':
case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (format_long == 2) {
+ GET_LS_VARG(llval);
+ __VA_LIST_PUT(vlist, long long, llval);
+ break;
+#ifdef __powerpc64__
+ } else if (format_long) {
+ GET_LS_VARG(ival);
+ switch (*p) {
+ case 'd':
+ case 'i':
+ __VA_LIST_PUT(vlist, long, (long)ival);
+ break;
+ default:
+ __VA_LIST_PUT(vlist, unsigned long,
+ (unsigned long)(unsigned int)ival);
+ break;
+ }
+ break;
+#endif /* __powerpc64__*/
+ }
+ /* fall through */
+ case 'c':
GET_LS_VARG(ival);
__VA_LIST_PUT(vlist, int, ival);
break;
+ case 'a':
+ case 'A':
case 'e':
case 'E':
case 'f':
@@ -566,63 +608,36 @@ static int __parse_printf_format(char *l
GET_LS_VARG(dval);
__VA_LIST_PUT(vlist, double, dval);
break;
- case 'h':
- GET_LS_VARG(ival);
- __VA_LIST_PUT(vlist, int, ival);
- if (p[1] == 'h') {
- p += 2;
- } else {
- p += 1;
- }
- break;
- case 'l':
- if (p[1] == 'l') {
- GET_LS_VARG(llval);
- __VA_LIST_PUT(vlist, long long, llval);
- p += 2;
- } else if (p[1] == 'f' || p[1] == 'F' || p[1] == 'e' || p[1] == 'E' || p[1] == 'g' || p[1] == 'G' ) {
- GET_LS_VARG(dval);
- __VA_LIST_PUT(vlist, double, dval);
- p += 2;
- } else {
- GET_LS_VARG(ival);
-#ifdef __powerpc64__
- if (p[1] == 'd') {
- __VA_LIST_PUT(vlist, long, (long)ival);
- }
- else {
- __VA_LIST_PUT(vlist, unsigned long,
- (unsigned long)(unsigned int)ival);
- }
-#else /* !__powerpc64__*/
- __VA_LIST_PUT(vlist, int, ival);
-#endif /* __powerpc64__*/
- p += 1;
- }
- break;
case 'p':
-#ifdef __powerpc64__
- GET_LS_VARG(ival);
- __VA_LIST_PUT(vlist, unsigned long,
- (unsigned long)(unsigned int)ival);
- break;
-#endif /* __powerpc64__ */
- case 'o':
- case 'u':
- case 'x':
- case 'X':
GET_LS_VARG(ival);
- __VA_LIST_PUT(vlist, int, ival);
+ __VA_LIST_PUT(vlist, unsigned long,
+ (unsigned long)(unsigned int)ival);
break;
case 's':
GET_LS_VARG(ls_offset);
- str = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, char *, str);
+ ptr = GET_LS_PTR(ls_offset);
+ __VA_LIST_PUT(vlist, char *, ptr);
+ break;
+ case 'n':
+ GET_LS_VARG(ls_offset);
+ ptr = GET_LS_PTR(ls_offset);
+#ifdef __powerpc64__
+ if (format_long == 1) {
+ vtemps->ptr = ptr;
+ __VA_LIST_PUT(vlist, long long *, &vtemps->llval);
+ vtemps++;
+ break;
+ }
+#endif /* __powerpc64__ */
+ __VA_LIST_PUT(vlist, void *, ptr);
break;
default:
break;
}
}
+#ifdef __powerpc64__
+ vtemps->ptr = NULL;
+#endif /* __powerpc64__ */
return 0;
}
@@ -633,45 +648,30 @@ static int __parse_scanf_format(char *ls
int fw;
int format_half, format_long, suppress;
unsigned int ls_offset;
- char *p, *pstart;
+ char *p;
void *ptr;
- if (nr_vargs == 0) {
-#ifdef __powerpc64__
- vtemps->ptr = NULL;
-#endif /* __powerpc64__ */
- return 0;
- }
-
- for (p = (char *) format, pstart = (char *) format; *p;) {
+ for (p = format; nr_vargs > 0 && *p; p++) {
p = strchr(p, '%');
if (!p) {
/* No more formatting. */
break;
}
p++;
+ nr_vargs--;
+ SKIP_SCANF_FLAG_CHARS(p, suppress);
SKIP_FIELD_WIDTH(p, fw, 0);
- SKIP_SCANF_FLAG_CHARS(p, format_half, format_long, suppress);
+ SKIP_LENGTH_MODIFIERS(p, format_half, format_long);
switch (*p) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
- if (format_half) {
- if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, short *, ptr);
- }
- } else if (format_long == 2) {
- if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, long long *, ptr);
- }
+ case 'X':
+ case 'n':
#ifdef __powerpc64__
- } else if (format_long) {
+ if (format_long == 1) {
if (!suppress) {
GET_LS_VARG(ls_offset);
ptr = GET_LS_PTR(ls_offset);
@@ -679,64 +679,39 @@ static int __parse_scanf_format(char *ls
__VA_LIST_PUT(vlist, long long *, &vtemps->llval);
vtemps++;
}
+ break;
+ }
#endif /* __powerpc64__ */
- } else {
- if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, int *, ptr);
- }
- }
- break;
+ /* fall through */
+ case 'a':
+ case 'A':
case 'e':
+ case 'E':
case 'f':
+ case 'F':
case 'g':
- if (format_long) {
- if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, double *, ptr);
- }
- } else {
- if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, float *, ptr);
- }
- }
- break;
- case 'n':
+ case 'G':
+ case 'c':
+ case 's':
if (!suppress) {
GET_LS_VARG(ls_offset);
ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, int *, ptr);
+ __VA_LIST_PUT(vlist, void *, ptr);
}
break;
case 'p':
if (!suppress) {
- GET_LS_VARG(ls_offset);
- ptr = GET_LS_PTR(ls_offset);
#ifdef __powerpc64__
- vtemps->ptr = ptr;
- __VA_LIST_PUT(vlist, long long *, &vtemps->llval);
- vtemps++;
-#else /* !__powerpc64__ */
- __VA_LIST_PUT(vlist, unsigned long *, ptr);
-#endif /* !__powerpc64__ */
- }
- break;
- case 'c':
- if (!suppress) {
GET_LS_VARG(ls_offset);
ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, char *, ptr);
- }
- break;
- case 's':
- if (!suppress) {
+ vtemps->ptr = ptr;
+ __VA_LIST_PUT(vlist, long long *, &vtemps->llval);
+ vtemps++;
+#else /* !__powerpc64__ */
GET_LS_VARG(ls_offset);
ptr = GET_LS_PTR(ls_offset);
- __VA_LIST_PUT(vlist, char *, ptr);
+ __VA_LIST_PUT(vlist, int *, ptr);
+#endif /* !__powerpc64__ */
}
break;
case '[':
@@ -1075,6 +1050,7 @@ static int default_c99_handler_vfprintf(
int rc, nr_vargs;
struct spe_va_list spe_vlist;
__va_elem *vlist;
+ struct __va_temp *vtemps; /* for %n in 64-bit PPC-ABI */
DEBUG_PRINTF("%s\n", __func__);
stream = get_FILE(arg0->slot[0]);
@@ -1082,8 +1058,15 @@ static int default_c99_handler_vfprintf(
memcpy(&spe_vlist, arg2, sizeof(struct spe_va_list));
nr_vargs = __nr_format_args(format);
vlist = __VA_LIST_ALLOCA(nr_vargs);
- rc = __parse_printf_format(ls, format, &spe_vlist, vlist, nr_vargs);
- rc = (rc == 0) ? __do_vfprintf(stream, format, vlist) : -1;
+ vtemps = __VA_TEMP_ALLOCA(nr_vargs);
+ rc = __parse_printf_format(ls, format, &spe_vlist, vlist, vtemps, nr_vargs);
+ if (rc == 0) {
+ rc = __do_vfprintf(stream, format, vlist);
+ __copy_va_temp(vtemps);
+ }
+ else {
+ rc = -1;
+ }
PUT_LS_RC(rc, 0, 0, errno);
return 0;
}
@@ -1147,6 +1130,7 @@ static int default_c99_handler_vprintf(c
int rc, nr_vargs;
struct spe_va_list spe_vlist;
__va_elem *vlist;
+ struct __va_temp *vtemps; /* for %n in 64-bit PPC-ABI */
DEBUG_PRINTF("%s\n", __func__);
stream = get_FILE(SPE_STDOUT);
@@ -1154,8 +1138,15 @@ static int default_c99_handler_vprintf(c
memcpy(&spe_vlist, arg1, sizeof(struct spe_va_list));
nr_vargs = __nr_format_args(format);
vlist = __VA_LIST_ALLOCA(nr_vargs);
- rc = __parse_printf_format(ls, format, &spe_vlist, vlist, nr_vargs);
- rc = (rc == 0) ? __do_vfprintf(stream, format, vlist) : -1;
+ vtemps = __VA_TEMP_ALLOCA(nr_vargs);
+ rc = __parse_printf_format(ls, format, &spe_vlist, vlist, vtemps, nr_vargs);
+ if (rc == 0) {
+ rc = __do_vfprintf(stream, format, vlist);
+ __copy_va_temp(vtemps);
+ }
+ else {
+ rc = -1;
+ }
PUT_LS_RC(rc, 0, 0, errno);
return 0;
}
@@ -1220,6 +1211,7 @@ static int default_c99_handler_vsnprintf
int rc, nr_vargs;
struct spe_va_list spe_vlist;
__va_elem *vlist;
+ struct __va_temp *vtemps; /* for %n in 64-bit PPC-ABI */
DEBUG_PRINTF("%s\n", __func__);
str = GET_LS_PTR(arg0->slot[0]);
@@ -1228,8 +1220,15 @@ static int default_c99_handler_vsnprintf
memcpy(&spe_vlist, arg3, sizeof(struct spe_va_list));
nr_vargs = __nr_format_args(format);
vlist = __VA_LIST_ALLOCA(nr_vargs);
- rc = __parse_printf_format(ls, format, &spe_vlist, vlist, nr_vargs);
- rc = (rc == 0) ? __do_vsnprintf(str, size, format, (void *) vlist) : -1;
+ vtemps = __VA_TEMP_ALLOCA(nr_vargs);
+ rc = __parse_printf_format(ls, format, &spe_vlist, vlist, vtemps, nr_vargs);
+ if (rc == 0) {
+ rc = __do_vsnprintf(str, size, format, vlist);
+ __copy_va_temp(vtemps);
+ }
+ else {
+ rc = -1;
+ }
PUT_LS_RC(rc, 0, 0, errno);
return 0;
}
@@ -1253,6 +1252,7 @@ static int default_c99_handler_vsprintf(
int rc, nr_vargs;
struct spe_va_list spe_vlist;
__va_elem *vlist;
+ struct __va_temp *vtemps; /* for %n in 64-bit PPC-ABI */
DEBUG_PRINTF("%s\n", __func__);
str = GET_LS_PTR(arg0->slot[0]);
@@ -1260,8 +1260,15 @@ static int default_c99_handler_vsprintf(
memcpy(&spe_vlist, arg2, sizeof(struct spe_va_list));
nr_vargs = __nr_format_args(format);
vlist = __VA_LIST_ALLOCA(nr_vargs);
- rc = __parse_printf_format(ls, format, &spe_vlist, vlist, nr_vargs);
- rc = (rc == 0) ? __do_vsprintf(str, format, vlist) : -1;
+ vtemps = __VA_TEMP_ALLOCA(nr_vargs);
+ rc = __parse_printf_format(ls, format, &spe_vlist, vlist, vtemps, nr_vargs);
+ if (rc == 0) {
+ rc = __do_vsprintf(str, format, vlist);
+ __copy_va_temp(vtemps);
+ }
+ else {
+ rc = -1;
+ }
PUT_LS_RC(rc, 0, 0, errno);
return 0;
}
More information about the cbe-oss-dev
mailing list