Skip to content

fcntl_fcntl_impl 1024 bytes limitation #95380

Open
@zenbooster

Description

@zenbooster

char buf[1024];

Why not allocate the buffer dynamically to remove this limitation? I am passing a structure to the driver that contains, among other things, the name of the target device of size PATH_MAX, and I do not fit into 1024 bytes. Everything works in the client in C, but not in python with your module.

Linked PRs

Activity

gst

gst commented on Jul 28, 2022

@gst
Contributor

something like that :

09:21 $ git diff
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c
index 9a8ec8dc98..3b7b9d8f1d 100644
--- a/Modules/fcntlmodule.c
+++ b/Modules/fcntlmodule.c
@@ -54,7 +54,6 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
     int ret;
     char *str;
     Py_ssize_t len;
-    char buf[1024];
     int async_err = 0;
 
     if (PySys_Audit("fcntl.fcntl", "iiO", fd, code, arg ? arg : Py_None) < 0) {
@@ -65,9 +64,10 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
         int parse_result;
 
         if (PyArg_Parse(arg, "s#", &str, &len)) {
-            if ((size_t)len > sizeof buf) {
-                PyErr_SetString(PyExc_ValueError,
-                                "fcntl string arg too long");
+            char* buf = malloc((size_t)len);
+            PyObject* buf_ret;
+            if (buf == NULL) {
+                PyErr_NoMemory();
                 return NULL;
             }
             memcpy(buf, str, len);
@@ -77,9 +77,12 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
                 Py_END_ALLOW_THREADS
             } while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
             if (ret < 0) {
+                free(buf);
                 return !async_err ? PyErr_SetFromErrno(PyExc_OSError) : NULL;
             }
-            return PyBytes_FromStringAndSize(buf, len);
+            buf_ret = PyBytes_FromStringAndSize(buf, len);
+            free(buf);
+            return buf_ret;
         }
 
         PyErr_Clear();

?

gst

gst commented on Jul 28, 2022

@gst
Contributor

I would be very happy to contribute and make the fix/MR by the way.

tiran

tiran commented on Jul 29, 2022

@tiran
Member

There is even a better way that avoids the extra memory allocation. You can create a new, empty bytes object and directly access its buffer. You are allowed to do this if the object is new and has not left the scope of the current C function.

PyObject *ret = PyBytes_FromStringAndSize(NULL, len);
if (ret == NULL) {
    return NULL;
}
char *buf = PyBytes_AS_STRING(ret);
memcpy(buf, str, len);
...
return ret;
zenbooster

zenbooster commented on Jul 29, 2022

@zenbooster
Author

There is even a better way that avoids the extra memory allocation. You can create a new, empty bytes object and directly access its buffer. You are allowed to do this if the object is new and has not left the scope of the current C function.

I like this option better.

Also, in the fcntl_ioctl_impl function, I removed adding zero to the end of the parameter for ioctl. Removed - works.

gst

gst commented on Jul 29, 2022

@gst
Contributor

I like this option better.

I did it like that :)

gst

gst commented on Jul 29, 2022

@gst
Contributor

@zenbooster

seems like we overlapped :)

not sure what is eventually best to do.

if you are ok with that : can you make a diff to my branch and I'll merge/cherry-pick the commit into it ?

arhadthedev

arhadthedev commented on Jul 29, 2022

@arhadthedev
Member

not sure what is eventually best to do.

Take everything of fcntl_fcntl_impl into gh-95429 and leave fcntl_ioctl_impl in gh-95439?

gst

gst commented on Jul 29, 2022

@gst
Contributor

Take everything of fcntl_fcntl_impl into #95429 and leave fcntl_ioctl_impl in #95439?

seems good for me.

so I can leave #95429 as is ?

arhadthedev

arhadthedev commented on Jul 29, 2022

@arhadthedev
Member

so I can leave #95429 as is ?

Right. BTW I forgot to preliminary check that the only difference between the PRs in fcntl_fcntl_impl is in names.

serhiy-storchaka

serhiy-storchaka commented on Apr 24, 2025

@serhiy-storchaka
Member

There may be an issue with this. Currently, when you pass too small buffer, you have still a chance to get reasonable (truncated) result or OSError. When you directly pass a small buffer to fcntl() or ioctl(), you have larger chance to get a segfault or memory corruption. It is a bug in your program, but severity of it will be changed, as well as a chance for recovery.

I think that it is safer to use that technique only for large buffer, and continue to use the temporary buffer for small arguments.

7 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtype-featureA feature request or enhancement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      fcntl_fcntl_impl 1024 bytes limitation · Issue #95380 · python/cpython

      Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

      Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant