diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c index 471fbb7ee6..60c90f7252 100644 --- a/src/backend/utils/adt/numutils.c +++ b/src/backend/utils/adt/numutils.c @@ -314,113 +314,119 @@ pg_strtoint32_safe(const char *s, Node *escontext) else if (*ptr == '+') ptr++; - /* process digits */ - if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) + /* process decimal digits */ + if (isdigit((unsigned char) ptr[0]) && + (isdigit((unsigned char) ptr[1]) || ptr[1] == '_' || ptr[1] == '\0' || isspace(ptr[1]))) { - firstdigit = ptr += 2; + firstdigit = ptr; while (*ptr) { - if (isxdigit((unsigned char) *ptr)) + if (isdigit((unsigned char) *ptr)) { - if (unlikely(tmp > -(PG_INT32_MIN / 16))) + if (unlikely(tmp > -(PG_INT32_MIN / 10))) goto out_of_range; - tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++]; + tmp = tmp * 10 + (*ptr++ - '0'); } else if (*ptr == '_') { - /* underscore must be followed by more digits */ + /* underscore may not be first */ + if (unlikely(ptr == firstdigit)) + goto invalid_syntax; + /* and it must be followed by more digits */ ptr++; - if (*ptr == '\0' || !isxdigit((unsigned char) *ptr)) + if (*ptr == '\0' || !isdigit((unsigned char) *ptr)) goto invalid_syntax; } else break; } } - else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O')) + /* process hex digits */ + else if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) { firstdigit = ptr += 2; while (*ptr) { - if (*ptr >= '0' && *ptr <= '7') + if (isxdigit((unsigned char) *ptr)) { - if (unlikely(tmp > -(PG_INT32_MIN / 8))) + if (unlikely(tmp > -(PG_INT32_MIN / 16))) goto out_of_range; - tmp = tmp * 8 + (*ptr++ - '0'); + tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++]; } else if (*ptr == '_') { /* underscore must be followed by more digits */ ptr++; - if (*ptr == '\0' || *ptr < '0' || *ptr > '7') + if (*ptr == '\0' || !isxdigit((unsigned char) *ptr)) goto invalid_syntax; } else break; } } - else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) + /* process octal digits */ + else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O')) { firstdigit = ptr += 2; while (*ptr) { - if (*ptr >= '0' && *ptr <= '1') + if (*ptr >= '0' && *ptr <= '7') { - if (unlikely(tmp > -(PG_INT32_MIN / 2))) + if (unlikely(tmp > -(PG_INT32_MIN / 8))) goto out_of_range; - tmp = tmp * 2 + (*ptr++ - '0'); + tmp = tmp * 8 + (*ptr++ - '0'); } else if (*ptr == '_') { /* underscore must be followed by more digits */ ptr++; - if (*ptr == '\0' || *ptr < '0' || *ptr > '1') + if (*ptr == '\0' || *ptr < '0' || *ptr > '7') goto invalid_syntax; } else break; } } - else + /* process binary digits */ + else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) { - firstdigit = ptr; + firstdigit = ptr += 2; while (*ptr) { - if (isdigit((unsigned char) *ptr)) + if (*ptr >= '0' && *ptr <= '1') { - if (unlikely(tmp > -(PG_INT32_MIN / 10))) + if (unlikely(tmp > -(PG_INT32_MIN / 2))) goto out_of_range; - tmp = tmp * 10 + (*ptr++ - '0'); + tmp = tmp * 2 + (*ptr++ - '0'); } else if (*ptr == '_') { - /* underscore may not be first */ - if (unlikely(ptr == firstdigit)) - goto invalid_syntax; - /* and it must be followed by more digits */ + /* underscore must be followed by more digits */ ptr++; - if (*ptr == '\0' || !isdigit((unsigned char) *ptr)) + if (*ptr == '\0' || *ptr < '0' || *ptr > '1') goto invalid_syntax; } else break; } } + else + goto invalid_syntax; /* require at least one digit */ if (unlikely(ptr == firstdigit)) goto invalid_syntax; /* allow trailing whitespace, but not other trailing chars */ - while (*ptr != '\0' && isspace((unsigned char) *ptr)) + while (isspace((unsigned char) *ptr)) ptr++; if (unlikely(*ptr != '\0'))