mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Fix bug
[ 555817 ] Flawed fcntl.ioctl implementation. with my patch that allows for an array to be mutated when passed as the buffer argument to ioctl() (details complicated by backwards compatibility considerations -- read the docs!).
This commit is contained in:
parent
122152451e
commit
f008998668
4 changed files with 171 additions and 18 deletions
|
@ -99,8 +99,62 @@ fcntl_ioctl(PyObject *self, PyObject *args)
|
|||
int ret;
|
||||
char *str;
|
||||
int len;
|
||||
int mutate_arg = 0;
|
||||
char buf[1024];
|
||||
|
||||
if (PyArg_ParseTuple(args, "O&iw#|i:ioctl",
|
||||
conv_descriptor, &fd, &code,
|
||||
&str, &len, &mutate_arg)) {
|
||||
char *arg;
|
||||
|
||||
if (PyTuple_Size(args) == 3) {
|
||||
/* warning goes here in 2.4 */
|
||||
mutate_arg = 0;
|
||||
}
|
||||
if (mutate_arg) {
|
||||
if (len <= sizeof buf) {
|
||||
memcpy(buf, str, len);
|
||||
arg = buf;
|
||||
}
|
||||
else {
|
||||
arg = str;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len > sizeof buf) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"ioctl string arg too long");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
memcpy(buf, str, len);
|
||||
arg = buf;
|
||||
}
|
||||
}
|
||||
if (buf == arg) {
|
||||
Py_BEGIN_ALLOW_THREADS /* think array.resize() */
|
||||
ret = ioctl(fd, code, arg);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
else {
|
||||
ret = ioctl(fd, code, arg);
|
||||
}
|
||||
if (mutate_arg && (len < sizeof buf)) {
|
||||
memcpy(str, buf, len);
|
||||
}
|
||||
if (ret < 0) {
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
if (mutate_arg) {
|
||||
return PyInt_FromLong(ret);
|
||||
}
|
||||
else {
|
||||
return PyString_FromStringAndSize(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
if (PyArg_ParseTuple(args, "O&is#:ioctl",
|
||||
conv_descriptor, &fd, &code, &str, &len)) {
|
||||
if (len > sizeof buf) {
|
||||
|
@ -123,7 +177,7 @@ fcntl_ioctl(PyObject *self, PyObject *args)
|
|||
arg = 0;
|
||||
if (!PyArg_ParseTuple(args,
|
||||
"O&i|i;ioctl requires a file or file descriptor,"
|
||||
" an integer and optionally a third integer or a string",
|
||||
" an integer and optionally a integer or buffer argument",
|
||||
conv_descriptor, &fd, &code, &arg)) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -138,17 +192,35 @@ fcntl_ioctl(PyObject *self, PyObject *args)
|
|||
}
|
||||
|
||||
PyDoc_STRVAR(ioctl_doc,
|
||||
"ioctl(fd, opt, [arg])\n\
|
||||
"ioctl(fd, opt[, arg[, mutate_flag]])\n\
|
||||
\n\
|
||||
Perform the requested operation on file descriptor fd. The operation\n\
|
||||
is defined by op and is operating system dependent. Typically these\n\
|
||||
codes can be retrieved from the library module IOCTL. The argument arg\n\
|
||||
is optional, and defaults to 0; it may be an int or a string. If arg is\n\
|
||||
given as a string, the return value of ioctl is a string of that length,\n\
|
||||
containing the resulting value put in the arg buffer by the operating system.\n\
|
||||
The length of the arg string is not allowed to exceed 1024 bytes. If the arg\n\
|
||||
given is an integer or if none is specified, the result value is an integer\n\
|
||||
corresponding to the return value of the ioctl call in the C code.");
|
||||
Perform the requested operation on file descriptor fd. The operation is\n\
|
||||
defined by op and is operating system dependent. Typically these codes are\n\
|
||||
retrieved from the fcntl or termios library modules.\n\
|
||||
\n\
|
||||
The argument arg is optional, and defaults to 0; it may be an int or a\n\
|
||||
buffer containing character data (most likely a string or an array). \n\
|
||||
\n\
|
||||
If the argument is a mutable buffer (such as an array) and if the\n\
|
||||
mutate_flag argument (which is only allowed in this case) is true then the\n\
|
||||
buffer is (in effect) passed to the operating system and changes made by\n\
|
||||
the OS will be reflected in the contents of the buffer after the call has\n\
|
||||
returned. The return value is the integer returned by the ioctl system\n\
|
||||
call.\n\
|
||||
\n\
|
||||
If the argument is a mutable buffer and the mutable_flag argument is not\n\
|
||||
passed or is false, the behavior is as if a string had been passed. This\n\
|
||||
behavior will change in future releases of Python.\n\
|
||||
\n\
|
||||
If the argument is an immutable buffer (most likely a string) then a copy\n\
|
||||
of the buffer is passed to the operating system and the return value is a\n\
|
||||
string of the same length containing whatever the operating system put in\n\
|
||||
the buffer. The length of the arg buffer in this case is not allowed to\n\
|
||||
exceed 1024 bytes.\n\
|
||||
\n\
|
||||
If the arg given is an integer or if none is specified, the result value is\n\
|
||||
an integer corresponding to the return value of the ioctl call in the C\n\
|
||||
code.");
|
||||
|
||||
|
||||
/* flock(fd, operation) */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue