summaryrefslogtreecommitdiffstats
path: root/Objects/stringobject.c
diff options
context:
space:
mode:
authorMarc-André Lemburg <mal@egenix.com>2000-06-30 10:29:57 (GMT)
committerMarc-André Lemburg <mal@egenix.com>2000-06-30 10:29:57 (GMT)
commitf28dd83b8670a6f21cacdcc2eb738766f51223c2 (patch)
tree533c04eb6e4d1baf8fc72ebf7ede96b35034427d /Objects/stringobject.c
parent587794b386aa6f1caf6b91585a88aa502217bd5f (diff)
downloadcpython-f28dd83b8670a6f21cacdcc2eb738766f51223c2.zip
cpython-f28dd83b8670a6f21cacdcc2eb738766f51223c2.tar.gz
cpython-f28dd83b8670a6f21cacdcc2eb738766f51223c2.tar.bz2
Marc-Andre Lemburg <mal@lemburg.com>:
New buffer overflow checks for formatting strings. By Trent Mick.
Diffstat (limited to 'Objects/stringobject.c')
-rw-r--r--Objects/stringobject.c94
1 files changed, 68 insertions, 26 deletions
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 10b43e4..5fe5b65 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -124,8 +124,13 @@ PyObject *
PyString_FromString(str)
const char *str;
{
- register unsigned int size = strlen(str);
+ register size_t size = strlen(str);
register PyStringObject *op;
+ if (size > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "string is too long for a Python string");
+ return NULL;
+ }
#ifndef DONT_SHARE_SHORT_STRINGS
if (size == 0 && (op = nullstring) != NULL) {
#ifdef COUNT_ALLOCS
@@ -237,9 +242,13 @@ static PyObject *
string_repr(op)
register PyStringObject *op;
{
- /* XXX overflow? */
- int newsize = 2 + 4 * op->ob_size * sizeof(char);
- PyObject *v = PyString_FromStringAndSize((char *)NULL, newsize);
+ size_t newsize = 2 + 4 * op->ob_size * sizeof(char);
+ PyObject *v;
+ if (newsize > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "string is too large to make repr");
+ }
+ v = PyString_FromStringAndSize((char *)NULL, newsize);
if (v == NULL) {
return NULL;
}
@@ -2335,36 +2344,52 @@ getnextarg(args, arglen, p_argidx)
#define F_ZERO (1<<4)
static int
-formatfloat(buf, flags, prec, type, v)
+formatfloat(buf, buflen, flags, prec, type, v)
char *buf;
+ size_t buflen;
int flags;
int prec;
int type;
PyObject *v;
{
+ /* fmt = '%#.' + `prec` + `type`
+ worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/
char fmt[20];
double x;
if (!PyArg_Parse(v, "d;float argument required", &x))
return -1;
if (prec < 0)
prec = 6;
- if (prec > 50)
- prec = 50; /* Arbitrary limitation */
if (type == 'f' && fabs(x)/1e25 >= 1e25)
type = 'g';
sprintf(fmt, "%%%s.%d%c", (flags&F_ALT) ? "#" : "", prec, type);
+ /* worst case length calc to ensure no buffer overrun:
+ fmt = %#.<prec>g
+ buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
+ for any double rep.)
+ len = 1 + prec + 1 + 2 + 5 = 9 + prec
+ If prec=0 the effective precision is 1 (the leading digit is
+ always given), therefore increase by one to 10+prec. */
+ if (buflen <= (size_t)10 + (size_t)prec) {
+ PyErr_SetString(PyExc_OverflowError,
+ "formatted float is too long (precision too long?)");
+ return -1;
+ }
sprintf(buf, fmt, x);
return strlen(buf);
}
static int
-formatint(buf, flags, prec, type, v)
+formatint(buf, buflen, flags, prec, type, v)
char *buf;
+ size_t buflen;
int flags;
int prec;
int type;
PyObject *v;
{
+ /* fmt = '%#.' + `prec` + 'l' + `type`
+ worst case length = 3 + 10 (len of INT_MAX) + 1 + 1 = 15 (use 20)*/
char fmt[20];
long x;
if (!PyArg_Parse(v, "l;int argument required", &x))
@@ -2372,15 +2397,24 @@ formatint(buf, flags, prec, type, v)
if (prec < 0)
prec = 1;
sprintf(fmt, "%%%s.%dl%c", (flags&F_ALT) ? "#" : "", prec, type);
+ /* buf = '+'/'-'/'0'/'0x' + '[0-9]'*max(prec,len(x in octal))
+ worst case buf = '0x' + [0-9]*prec, where prec >= 11 */
+ if (buflen <= 13 || buflen <= (size_t)2+(size_t)prec) {
+ PyErr_SetString(PyExc_OverflowError,
+ "formatted integer is too long (precision too long?)");
+ return -1;
+ }
sprintf(buf, fmt, x);
return strlen(buf);
}
static int
-formatchar(buf, v)
+formatchar(buf, buflen, v)
char *buf;
+ size_t buflen;
PyObject *v;
{
+ /* presume that the buffer is at least 2 characters long */
if (PyString_Check(v)) {
if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0]))
return -1;
@@ -2394,7 +2428,15 @@ formatchar(buf, v)
}
-/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) */
+/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...)
+
+ FORMATBUFLEN is the length of the buffer in which the floats, ints, &
+ chars are formatted. XXX This is a magic number. Each formatting
+ routine does bounds checking to ensure no overflow, but a better
+ solution may be to malloc a buffer of appropriate size for each
+ format. For now, the current solution is sufficient.
+*/
+#define FORMATBUFLEN (size_t)120
PyObject *
PyString_Format(format, args)
@@ -2451,10 +2493,10 @@ PyString_Format(format, args)
int fill;
PyObject *v = NULL;
PyObject *temp = NULL;
- char *buf;
+ char *pbuf;
int sign;
int len;
- char tmpbuf[120]; /* For format{float,int,char}() */
+ char formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */
char *fmt_start = fmt;
fmt++;
@@ -2602,7 +2644,7 @@ PyString_Format(format, args)
fill = ' ';
switch (c) {
case '%':
- buf = "%";
+ pbuf = "%";
len = 1;
break;
case 's':
@@ -2622,7 +2664,7 @@ PyString_Format(format, args)
"%s argument has non-string str()");
goto error;
}
- buf = PyString_AsString(temp);
+ pbuf = PyString_AsString(temp);
len = PyString_Size(temp);
if (prec >= 0 && len > prec)
len = prec;
@@ -2635,8 +2677,8 @@ PyString_Format(format, args)
case 'X':
if (c == 'i')
c = 'd';
- buf = tmpbuf;
- len = formatint(buf, flags, prec, c, v);
+ pbuf = formatbuf;
+ len = formatint(pbuf, sizeof(formatbuf), flags, prec, c, v);
if (len < 0)
goto error;
sign = (c == 'd');
@@ -2644,9 +2686,9 @@ PyString_Format(format, args)
fill = '0';
if ((flags&F_ALT) &&
(c == 'x' || c == 'X') &&
- buf[0] == '0' && buf[1] == c) {
- *res++ = *buf++;
- *res++ = *buf++;
+ pbuf[0] == '0' && pbuf[1] == c) {
+ *res++ = *pbuf++;
+ *res++ = *pbuf++;
rescnt -= 2;
len -= 2;
width -= 2;
@@ -2660,8 +2702,8 @@ PyString_Format(format, args)
case 'f':
case 'g':
case 'G':
- buf = tmpbuf;
- len = formatfloat(buf, flags, prec, c, v);
+ pbuf = formatbuf;
+ len = formatfloat(pbuf, sizeof(formatbuf), flags, prec, c, v);
if (len < 0)
goto error;
sign = 1;
@@ -2669,8 +2711,8 @@ PyString_Format(format, args)
fill = '0';
break;
case 'c':
- buf = tmpbuf;
- len = formatchar(buf, v);
+ pbuf = formatbuf;
+ len = formatchar(pbuf, sizeof(formatbuf), v);
if (len < 0)
goto error;
break;
@@ -2681,8 +2723,8 @@ PyString_Format(format, args)
goto error;
}
if (sign) {
- if (*buf == '-' || *buf == '+') {
- sign = *buf++;
+ if (*pbuf == '-' || *pbuf == '+') {
+ sign = *pbuf++;
len--;
}
else if (flags & F_SIGN)
@@ -2718,7 +2760,7 @@ PyString_Format(format, args)
}
if (sign && fill == ' ')
*res++ = sign;
- memcpy(res, buf, len);
+ memcpy(res, pbuf, len);
res += len;
rescnt -= len;
while (--width >= len) {