mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #25761: Improved error reporting about truncated pickle data in
C implementation of unpickler. UnpicklingError is now raised instead of AttributeError and ValueError in some cases.
This commit is contained in:
parent
df6ff7bcca
commit
90493ab30c
3 changed files with 46 additions and 41 deletions
|
@ -139,8 +139,7 @@ if has_c_implementation:
|
||||||
class CUnpicklerTests(PyUnpicklerTests):
|
class CUnpicklerTests(PyUnpicklerTests):
|
||||||
unpickler = _pickle.Unpickler
|
unpickler = _pickle.Unpickler
|
||||||
bad_stack_errors = (pickle.UnpicklingError,)
|
bad_stack_errors = (pickle.UnpicklingError,)
|
||||||
truncated_errors = (pickle.UnpicklingError, EOFError,
|
truncated_errors = (pickle.UnpicklingError,)
|
||||||
AttributeError, ValueError)
|
|
||||||
|
|
||||||
class CPicklerTests(PyPicklerTests):
|
class CPicklerTests(PyPicklerTests):
|
||||||
pickler = _pickle.Pickler
|
pickler = _pickle.Pickler
|
||||||
|
|
|
@ -89,6 +89,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #25761: Improved error reporting about truncated pickle data in
|
||||||
|
C implementation of unpickler. UnpicklingError is now raised instead of
|
||||||
|
AttributeError and ValueError in some cases.
|
||||||
|
|
||||||
- Issue #26798: Add BLAKE2 (blake2b and blake2s) to hashlib.
|
- Issue #26798: Add BLAKE2 (blake2b and blake2s) to hashlib.
|
||||||
|
|
||||||
- Issue #25596: Optimized glob() and iglob() functions in the
|
- Issue #25596: Optimized glob() and iglob() functions in the
|
||||||
|
|
|
@ -1091,6 +1091,14 @@ _Unpickler_SetStringInput(UnpicklerObject *self, PyObject *input)
|
||||||
return self->input_len;
|
return self->input_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bad_readline(void)
|
||||||
|
{
|
||||||
|
PickleState *st = _Pickle_GetGlobalState();
|
||||||
|
PyErr_SetString(st->UnpicklingError, "pickle data was truncated");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_Unpickler_SkipConsumed(UnpicklerObject *self)
|
_Unpickler_SkipConsumed(UnpicklerObject *self)
|
||||||
{
|
{
|
||||||
|
@ -1195,17 +1203,14 @@ _Unpickler_ReadImpl(UnpicklerObject *self, char **s, Py_ssize_t n)
|
||||||
/* This case is handled by the _Unpickler_Read() macro for efficiency */
|
/* This case is handled by the _Unpickler_Read() macro for efficiency */
|
||||||
assert(self->next_read_idx + n > self->input_len);
|
assert(self->next_read_idx + n > self->input_len);
|
||||||
|
|
||||||
if (!self->read) {
|
if (!self->read)
|
||||||
PyErr_Format(PyExc_EOFError, "Ran out of input");
|
return bad_readline();
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
num_read = _Unpickler_ReadFromFile(self, n);
|
num_read = _Unpickler_ReadFromFile(self, n);
|
||||||
if (num_read < 0)
|
if (num_read < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (num_read < n) {
|
if (num_read < n)
|
||||||
PyErr_Format(PyExc_EOFError, "Ran out of input");
|
return bad_readline();
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
*s = self->input_buffer;
|
*s = self->input_buffer;
|
||||||
self->next_read_idx = n;
|
self->next_read_idx = n;
|
||||||
return n;
|
return n;
|
||||||
|
@ -1249,7 +1254,7 @@ _Unpickler_CopyLine(UnpicklerObject *self, char *line, Py_ssize_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read a line from the input stream/buffer. If we run off the end of the input
|
/* Read a line from the input stream/buffer. If we run off the end of the input
|
||||||
before hitting \n, return the data we found.
|
before hitting \n, raise an error.
|
||||||
|
|
||||||
Returns the number of chars read, or -1 on failure. */
|
Returns the number of chars read, or -1 on failure. */
|
||||||
static Py_ssize_t
|
static Py_ssize_t
|
||||||
|
@ -1265,20 +1270,16 @@ _Unpickler_Readline(UnpicklerObject *self, char **result)
|
||||||
return _Unpickler_CopyLine(self, line_start, num_read, result);
|
return _Unpickler_CopyLine(self, line_start, num_read, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self->read) {
|
if (!self->read)
|
||||||
|
return bad_readline();
|
||||||
|
|
||||||
num_read = _Unpickler_ReadFromFile(self, READ_WHOLE_LINE);
|
num_read = _Unpickler_ReadFromFile(self, READ_WHOLE_LINE);
|
||||||
if (num_read < 0)
|
if (num_read < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
if (num_read == 0 || self->input_buffer[num_read - 1] != '\n')
|
||||||
|
return bad_readline();
|
||||||
self->next_read_idx = num_read;
|
self->next_read_idx = num_read;
|
||||||
return _Unpickler_CopyLine(self, self->input_buffer, num_read, result);
|
return _Unpickler_CopyLine(self, self->input_buffer, num_read, result);
|
||||||
}
|
|
||||||
|
|
||||||
/* If we get here, we've run off the end of the input string. Return the
|
|
||||||
remaining string and let the caller figure it out. */
|
|
||||||
*result = self->input_buffer + self->next_read_idx;
|
|
||||||
num_read = i - self->next_read_idx;
|
|
||||||
self->next_read_idx = i;
|
|
||||||
return num_read;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns -1 (with an exception set) on failure, 0 on success. The memo array
|
/* Returns -1 (with an exception set) on failure, 0 on success. The memo array
|
||||||
|
@ -4599,14 +4600,6 @@ load_none(UnpicklerObject *self)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
bad_readline(void)
|
|
||||||
{
|
|
||||||
PickleState *st = _Pickle_GetGlobalState();
|
|
||||||
PyErr_SetString(st->UnpicklingError, "pickle data was truncated");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
load_int(UnpicklerObject *self)
|
load_int(UnpicklerObject *self)
|
||||||
{
|
{
|
||||||
|
@ -6245,8 +6238,13 @@ load(UnpicklerObject *self)
|
||||||
case opcode: if (load_func(self, (arg)) < 0) break; continue;
|
case opcode: if (load_func(self, (arg)) < 0) break; continue;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (_Unpickler_Read(self, &s, 1) < 0)
|
if (_Unpickler_Read(self, &s, 1) < 0) {
|
||||||
break;
|
PickleState *st = _Pickle_GetGlobalState();
|
||||||
|
if (PyErr_ExceptionMatches(st->UnpicklingError)) {
|
||||||
|
PyErr_Format(PyExc_EOFError, "Ran out of input");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
switch ((enum opcode)s[0]) {
|
switch ((enum opcode)s[0]) {
|
||||||
OP(NONE, load_none)
|
OP(NONE, load_none)
|
||||||
|
@ -6318,16 +6316,20 @@ load(UnpicklerObject *self)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (s[0] == '\0') {
|
{
|
||||||
PyErr_SetNone(PyExc_EOFError);
|
PickleState *st = _Pickle_GetGlobalState();
|
||||||
|
unsigned char c = (unsigned char) *s;
|
||||||
|
if (0x20 <= c && c <= 0x7e && c != '\'' && c != '\\') {
|
||||||
|
PyErr_Format(st->UnpicklingError,
|
||||||
|
"invalid load key, '%c'.", c);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PickleState *st = _Pickle_GetGlobalState();
|
|
||||||
PyErr_Format(st->UnpicklingError,
|
PyErr_Format(st->UnpicklingError,
|
||||||
"invalid load key, '%c'.", s[0]);
|
"invalid load key, '\\x%02x'.", c);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break; /* and we are done! */
|
break; /* and we are done! */
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue