summaryrefslogtreecommitdiffstats
path: root/Modules/zipimport.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/zipimport.c')
-rw-r--r--Modules/zipimport.c80
1 files changed, 56 insertions, 24 deletions
diff --git a/Modules/zipimport.c b/Modules/zipimport.c
index 2feb2a8..4594dd4 100644
--- a/Modules/zipimport.c
+++ b/Modules/zipimport.c
@@ -14,6 +14,10 @@ struct st_zip_searchorder {
int type;
};
+#ifdef ALTSEP
+_Py_IDENTIFIER(replace);
+#endif
+
/* zip_searchorder defines how we search for a module in the Zip
archive: we first search for a package __init__, then for
non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries
@@ -66,9 +70,6 @@ zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
PyObject *path, *files, *tmp;
PyObject *filename = NULL;
Py_ssize_t len, flen;
-#ifdef ALTSEP
- _Py_IDENTIFIER(replace);
-#endif
if (!_PyArg_NoKeywords("zipimporter()", kwds))
return -1;
@@ -117,6 +118,8 @@ zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds)
if (flen == -1)
break;
filename = PyUnicode_Substring(path, 0, flen);
+ if (filename == NULL)
+ goto error;
}
if (filename == NULL) {
PyErr_SetString(ZipImportError, "not a Zip file");
@@ -230,7 +233,7 @@ make_filename(PyObject *prefix, PyObject *name)
Py_ssize_t len;
len = PyUnicode_GET_LENGTH(prefix) + PyUnicode_GET_LENGTH(name) + 1;
- p = buf = PyMem_Malloc(sizeof(Py_UCS4) * len);
+ p = buf = PyMem_New(Py_UCS4, len);
if (buf == NULL) {
PyErr_NoMemory();
return NULL;
@@ -469,10 +472,13 @@ zipimporter_load_module(PyObject *obj, PyObject *args)
if (ispackage) {
/* add __path__ to the module *before* the code gets
executed */
- PyObject *pkgpath, *fullpath;
- PyObject *subname = get_subname(fullname);
+ PyObject *pkgpath, *fullpath, *subname;
int err;
+ subname = get_subname(fullname);
+ if (subname == NULL)
+ goto error;
+
fullpath = PyUnicode_FromFormat("%U%c%U%U",
self->archive, SEP,
self->prefix, subname);
@@ -554,9 +560,6 @@ zipimporter_get_data(PyObject *obj, PyObject *args)
{
ZipImporter *self = (ZipImporter *)obj;
PyObject *path, *key;
-#ifdef ALTSEP
- _Py_IDENTIFIER(replace);
-#endif
PyObject *toc_entry;
Py_ssize_t path_start, path_len, len;
@@ -862,6 +865,7 @@ read_directory(PyObject *archive)
long l, count;
Py_ssize_t i;
char name[MAXPATHLEN + 5];
+ char dummy[8]; /* Buffer to read unused header values into */
PyObject *nameobj = NULL;
char *p, endof_central_dir[22];
Py_ssize_t arc_offset; /* Absolute offset to start of the zip-archive. */
@@ -869,7 +873,7 @@ read_directory(PyObject *archive)
const char *charset;
int bootstrap;
- fp = _Py_fopen(archive, "rb");
+ fp = _Py_fopen_obj(archive, "rb");
if (fp == NULL) {
if (!PyErr_Occurred())
PyErr_Format(ZipImportError, "can't open Zip file: %R", archive);
@@ -905,17 +909,25 @@ read_directory(PyObject *archive)
/* Start of Central Directory */
count = 0;
+ if (fseek(fp, header_offset, 0) == -1)
+ goto file_error;
for (;;) {
PyObject *t;
int err;
- if (fseek(fp, header_offset, 0) == -1) /* Start of file header */
- goto fseek_error;
+ /* Start of file header */
l = PyMarshal_ReadLongFromFile(fp);
+ if (l == -1 && PyErr_Occurred())
+ goto error;
if (l != 0x02014B50)
break; /* Bad: Central Dir File Header */
- if (fseek(fp, header_offset + 8, 0) == -1)
- goto fseek_error;
+
+ /* On Windows, calling fseek to skip over the fields we don't use is
+ slower than reading the data into a dummy buffer because fseek flushes
+ stdio's internal buffers. See issue #8745. */
+ if (fread(dummy, 1, 4, fp) != 4) /* Skip unused fields, avoid fseek */
+ goto file_error;
+
flags = (unsigned short)PyMarshal_ReadShortFromFile(fp);
compress = PyMarshal_ReadShortFromFile(fp);
time = PyMarshal_ReadShortFromFile(fp);
@@ -924,12 +936,15 @@ read_directory(PyObject *archive)
data_size = PyMarshal_ReadLongFromFile(fp);
file_size = PyMarshal_ReadLongFromFile(fp);
name_size = PyMarshal_ReadShortFromFile(fp);
- header_size = 46 + name_size +
+ header_size = name_size +
PyMarshal_ReadShortFromFile(fp) +
PyMarshal_ReadShortFromFile(fp);
- if (fseek(fp, header_offset + 42, 0) == -1)
- goto fseek_error;
+ if (fread(dummy, 1, 8, fp) != 8) /* Skip unused fields, avoid fseek */
+ goto file_error;
file_offset = PyMarshal_ReadLongFromFile(fp) + arc_offset;
+ if (PyErr_Occurred())
+ goto error;
+
if (name_size > MAXPATHLEN)
name_size = MAXPATHLEN;
@@ -941,7 +956,9 @@ read_directory(PyObject *archive)
p++;
}
*p = 0; /* Add terminating null byte */
- header_offset += header_size;
+ for (; i < header_size; i++) /* Skip the rest of the header */
+ if(getc(fp) == EOF) /* Avoid fseek */
+ goto file_error;
bootstrap = 0;
if (flags & 0x0800)
@@ -988,7 +1005,7 @@ read_directory(PyObject *archive)
PySys_FormatStderr("# zipimport: found %ld names in %R\n",
count, archive);
return files;
-fseek_error:
+file_error:
fclose(fp);
Py_XDECREF(files);
Py_XDECREF(nameobj);
@@ -1054,8 +1071,12 @@ get_data(PyObject *archive, PyObject *toc_entry)
&date, &crc)) {
return NULL;
}
+ if (data_size < 0) {
+ PyErr_Format(ZipImportError, "negative data size");
+ return NULL;
+ }
- fp = _Py_fopen(archive, "rb");
+ fp = _Py_fopen_obj(archive, "rb");
if (!fp) {
if (!PyErr_Occurred())
PyErr_Format(PyExc_IOError,
@@ -1073,9 +1094,10 @@ get_data(PyObject *archive, PyObject *toc_entry)
l = PyMarshal_ReadLongFromFile(fp);
if (l != 0x04034B50) {
/* Bad: Local File Header */
- PyErr_Format(ZipImportError,
- "bad local file header in %U",
- archive);
+ if (!PyErr_Occurred())
+ PyErr_Format(ZipImportError,
+ "bad local file header in %U",
+ archive);
fclose(fp);
return NULL;
}
@@ -1087,8 +1109,17 @@ get_data(PyObject *archive, PyObject *toc_entry)
l = 30 + PyMarshal_ReadShortFromFile(fp) +
PyMarshal_ReadShortFromFile(fp); /* local header size */
+ if (PyErr_Occurred()) {
+ fclose(fp);
+ return NULL;
+ }
file_offset += l; /* Start of file data */
+ if (data_size > LONG_MAX - 1) {
+ fclose(fp);
+ PyErr_NoMemory();
+ return NULL;
+ }
bytes_size = compress == 0 ? data_size : data_size + 1;
if (bytes_size == 0)
bytes_size++;
@@ -1105,6 +1136,7 @@ get_data(PyObject *archive, PyObject *toc_entry)
bytes_read = fread(buf, 1, data_size, fp);
} else {
fclose(fp);
+ Py_DECREF(raw_data);
PyErr_Format(ZipImportError, "can't read Zip file: %R", archive);
return NULL;
}
@@ -1249,7 +1281,7 @@ normalize_line_endings(PyObject *source)
}
/* Given a string buffer containing Python source code, compile it
- return and return a code object as a new reference. */
+ and return a code object as a new reference. */
static PyObject *
compile_source(PyObject *pathname, PyObject *source)
{