summaryrefslogtreecommitdiff
path: root/numpy/f2py/src/fortranobject.c
diff options
context:
space:
mode:
authorLars Buitinck <larsmans@gmail.com>2014-09-27 16:40:24 +0200
committerLars Buitinck <larsmans@gmail.com>2014-09-28 15:31:58 +0200
commitb356ef022e2b6bb3ae6290281e25454475a2a16a (patch)
treef08f93f9f21b7e66410788e240009260144ddb95 /numpy/f2py/src/fortranobject.c
parentf4fa7bd2a67a577eaa72af83028adcfbc71b7fd4 (diff)
downloadnumpy-b356ef022e2b6bb3ae6290281e25454475a2a16a.tar.gz
MAINT: f2py: rewrite fortran_doc
Should not use sprintf, and certainly not with incorrect error checking (gh-5044). Entirely rewritten for readability. Also replaced a few sprintf calls that were just copying strings without interpretation by the simpler and possibly faster strcpy/strcat. (These need to be replaced by something more sensible.)
Diffstat (limited to 'numpy/f2py/src/fortranobject.c')
-rw-r--r--numpy/f2py/src/fortranobject.c192
1 files changed, 124 insertions, 68 deletions
diff --git a/numpy/f2py/src/fortranobject.c b/numpy/f2py/src/fortranobject.c
index 0e23c4c37..001a4c7de 100644
--- a/numpy/f2py/src/fortranobject.c
+++ b/numpy/f2py/src/fortranobject.c
@@ -5,6 +5,9 @@
extern "C" {
#endif
+#include <stdlib.h>
+#include <string.h>
+
/*
This file implements: FortranObject, array_from_pyobj, copy_ND_array
@@ -100,88 +103,141 @@ static PyMethodDef fortran_methods[] = {
#endif
-static PyObject *
-fortran_doc (FortranDataDef def) {
- char *p;
- /*
- p is used as a buffer to hold generated documentation strings.
- A common operation in generating the documentation strings, is
- appending a string to the buffer p. Earlier, the following
- idiom was:
+/* Returns number of bytes consumed from buf, or -1 on error. */
+static Py_ssize_t
+format_def(char *buf, Py_ssize_t size, FortranDataDef def)
+{
+ char *p = buf;
+ int i, n;
+
+ n = PyOS_snprintf(p, size, "array(%" NPY_INTP_FMT, def.dims.d[0]);
+ if (n < 0 || n >= size) {
+ return -1;
+ }
+ p += n;
+ size -= n;
- sprintf(p, "%s<string to be appended>", p);
+ for (i = 1; i < def.rank; i++) {
+ n = PyOS_snprintf(p, size, ",%" NPY_INTP_FMT, def.dims.d[i]);
+ if (n < 0 || n >= size) {
+ return -1;
+ }
+ p += n;
+ size -= n;
+ }
- but this does not work when _FORTIFY_SOURCE=2 is enabled: instead
- of appending the string, the string is inserted.
+ if (size <= 0) {
+ return -1;
+ }
- As a fix, the following idiom should be used for appending
- strings to a buffer p:
+ p[size] = ')';
+ p++;
+ size--;
- sprintf(p + strlen(p), "<string to be appended>");
- */
+ if (def.data == NULL) {
+ static const char notalloc[] = ", not allocated";
+ if (size < sizeof(notalloc)) {
+ return -1;
+ }
+ memcpy(p, notalloc, sizeof(notalloc));
+ }
+
+ return p - buf;
+}
+
+static PyObject *
+fortran_doc(FortranDataDef def)
+{
+ char *buf, *p;
PyObject *s = NULL;
- int i;
- unsigned size=100;
- if (def.doc!=NULL)
+ Py_ssize_t n, origsize, size = 100;
+
+ if (def.doc != NULL) {
size += strlen(def.doc);
- p = (char*)malloc (size);
- if (p==NULL) {
- /* No need to call free() because p is NULL */
+ }
+ origsize = size;
+ buf = p = (char *)PyMem_Malloc(size);
+ if (buf == NULL) {
return PyErr_NoMemory();
}
- p[0] = '\0'; /* make sure that the buffer has zero length */
- if (def.rank==-1) {
- if (def.doc==NULL) {
- if (sprintf(p,"%s - ",def.name)==0) goto fail;
- if (sprintf(p+strlen(p),"no docs available")==0)
+
+ if (def.rank == -1) {
+ if (def.doc) {
+ n = strlen(def.doc);
+ if (n > size) {
goto fail;
- } else {
- if (sprintf(p+strlen(p),"%s",def.doc)==0)
+ }
+ memcpy(p, def.doc, n);
+ p += n;
+ size -= n;
+ }
+ else {
+ n = PyOS_snprintf(p, size, "%s - no docs available", def.name);
+ if (n < 0 || n >= size) {
goto fail;
+ }
+ p += n;
+ size -= n;
}
- } else {
+ }
+ else {
PyArray_Descr *d = PyArray_DescrFromType(def.type);
- if (sprintf(p+strlen(p),"'%c'-",d->type)==0) {
- Py_DECREF(d);
- goto fail;
- }
+ n = PyOS_snprintf(p, size, "'%c'-", d->type);
Py_DECREF(d);
- if (def.data==NULL) {
- if (sprintf(p+strlen(p),"array(%" NPY_INTP_FMT,def.dims.d[0])==0)
- goto fail;
- for(i=1;i<def.rank;++i)
- if (sprintf(p+strlen(p),",%" NPY_INTP_FMT,def.dims.d[i])==0)
- goto fail;
- if (sprintf(p+strlen(p),"), not allocated")==0)
- goto fail;
- } else {
- if (def.rank>0) {
- if (sprintf(p+strlen(p),"array(%"NPY_INTP_FMT,def.dims.d[0])==0)
- goto fail;
- for(i=1;i<def.rank;i++)
- if (sprintf(p+strlen(p),",%" NPY_INTP_FMT,def.dims.d[i])==0)
- goto fail;
- if (sprintf(p+strlen(p),")")==0) goto fail;
- } else {
- if (sprintf(p+strlen(p),"scalar")==0) goto fail;
+ if (n < 0 || n >= size) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+
+ if (def.data == NULL) {
+ n = format_def(p, size, def) == -1;
+ if (n < 0) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+ }
+ else if (def.rank > 0) {
+ n = format_def(p, size, def);
+ if (n < 0) {
+ goto fail;
+ }
+ p += n;
+ size -= n;
+ }
+ else {
+ n = strlen("scalar");
+ if (size < n) {
+ goto fail;
}
+ memcpy(p, "scalar", n);
+ p += n;
+ size -= n;
}
}
- if (sprintf(p+strlen(p),"\n")==0) goto fail;
- if (strlen(p)>size) {
- fprintf(stderr,"fortranobject.c:fortran_doc:len(p)=%zd>%d(size):"\
- " too long doc string required, increase size\n",\
- strlen(p),size);
+ if (size <= 1) {
goto fail;
}
+ *p++ = '\n';
+ size--;
+
+ /* p now points one beyond the last character of the string in buf */
#if PY_VERSION_HEX >= 0x03000000
- s = PyUnicode_FromString(p);
+ s = PyUnicode_FromStringAndSize(buf, p - buf);
#else
- s = PyString_FromString(p);
+ s = PyString_FromStringAndSize(buf, p - buf);
#endif
- fail:
- free(p);
+
+ PyMem_Free(buf);
return s;
+
+ fail:
+ fprintf(stderr, "fortranobject.c: fortran_doc: len(p)=%zd>%zd=size:"
+ " too long docstring required, increase size\n",
+ p - buf, origsize);
+ PyMem_Free(buf);
+ return NULL;
}
static FortranDataDef *save_def; /* save pointer of an allocatable array */
@@ -623,11 +679,11 @@ PyArrayObject* array_from_pyobj(const int type_num,
/* intent(cache), optional, intent(hide) */
if (count_nonpos(rank,dims)) {
int i;
- sprintf(mess,"failed to create intent(cache|hide)|optional array"
- "-- must have defined dimensions but got (");
+ strcpy(mess, "failed to create intent(cache|hide)|optional array"
+ "-- must have defined dimensions but got (");
for(i=0;i<rank;++i)
sprintf(mess+strlen(mess),"%" NPY_INTP_FMT ",",dims[i]);
- sprintf(mess+strlen(mess),")");
+ strcat(mess, ")");
PyErr_SetString(PyExc_ValueError,mess);
return NULL;
}
@@ -660,9 +716,9 @@ PyArrayObject* array_from_pyobj(const int type_num,
Py_INCREF(obj);
return (PyArrayObject *)obj;
}
- sprintf(mess,"failed to initialize intent(cache) array");
+ strcpy(mess, "failed to initialize intent(cache) array");
if (!PyArray_ISONESEGMENT(obj))
- sprintf(mess+strlen(mess)," -- input must be in one segment");
+ strcat(mess, " -- input must be in one segment");
if (PyArray_ITEMSIZE(arr)<elsize)
sprintf(mess+strlen(mess)," -- expected at least elsize=%d but got %d",
elsize,PyArray_ITEMSIZE(arr)
@@ -698,11 +754,11 @@ PyArrayObject* array_from_pyobj(const int type_num,
}
if (intent & F2PY_INTENT_INOUT) {
- sprintf(mess,"failed to initialize intent(inout) array");
+ strcpy(mess, "failed to initialize intent(inout) array");
if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr))
- sprintf(mess+strlen(mess)," -- input not contiguous");
+ strcat(mess, " -- input not contiguous");
if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr))
- sprintf(mess+strlen(mess)," -- input not fortran contiguous");
+ strcat(mess, " -- input not fortran contiguous");
if (PyArray_ITEMSIZE(arr)!=elsize)
sprintf(mess+strlen(mess)," -- expected elsize=%d but got %d",
elsize,