Skip to content

gh-116541: Handle errors correctly in _pystatvfs_fromstructstatvfs #116542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 36 additions & 32 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -12970,46 +12970,50 @@ _pystatvfs_fromstructstatvfs(PyObject *module, struct statvfs st) {
if (v == NULL)
return NULL;

int pos = 0;

#define SET_RESULT(CALL) \
do { \
PyObject *item = (CALL); \
if (item == NULL) { \
Py_DECREF(v); \
return NULL; \
} \
PyStructSequence_SET_ITEM(v, pos++, item); \
} while(0)

#if !defined(HAVE_LARGEFILE_SUPPORT)
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
PyStructSequence_SET_ITEM(v, 2, PyLong_FromLong((long) st.f_blocks));
PyStructSequence_SET_ITEM(v, 3, PyLong_FromLong((long) st.f_bfree));
PyStructSequence_SET_ITEM(v, 4, PyLong_FromLong((long) st.f_bavail));
PyStructSequence_SET_ITEM(v, 5, PyLong_FromLong((long) st.f_files));
PyStructSequence_SET_ITEM(v, 6, PyLong_FromLong((long) st.f_ffree));
PyStructSequence_SET_ITEM(v, 7, PyLong_FromLong((long) st.f_favail));
PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
SET_RESULT(PyLong_FromLong((long) st.f_bsize));
SET_RESULT(PyLong_FromLong((long) st.f_frsize));
SET_RESULT(PyLong_FromLong((long) st.f_blocks));
SET_RESULT(PyLong_FromLong((long) st.f_bfree));
SET_RESULT(PyLong_FromLong((long) st.f_bavail));
SET_RESULT(PyLong_FromLong((long) st.f_files));
SET_RESULT(PyLong_FromLong((long) st.f_ffree));
SET_RESULT(PyLong_FromLong((long) st.f_favail));
SET_RESULT(PyLong_FromLong((long) st.f_flag));
SET_RESULT(PyLong_FromLong((long) st.f_namemax));
#else
PyStructSequence_SET_ITEM(v, 0, PyLong_FromLong((long) st.f_bsize));
PyStructSequence_SET_ITEM(v, 1, PyLong_FromLong((long) st.f_frsize));
PyStructSequence_SET_ITEM(v, 2,
PyLong_FromLongLong((long long) st.f_blocks));
PyStructSequence_SET_ITEM(v, 3,
PyLong_FromLongLong((long long) st.f_bfree));
PyStructSequence_SET_ITEM(v, 4,
PyLong_FromLongLong((long long) st.f_bavail));
PyStructSequence_SET_ITEM(v, 5,
PyLong_FromLongLong((long long) st.f_files));
PyStructSequence_SET_ITEM(v, 6,
PyLong_FromLongLong((long long) st.f_ffree));
PyStructSequence_SET_ITEM(v, 7,
PyLong_FromLongLong((long long) st.f_favail));
PyStructSequence_SET_ITEM(v, 8, PyLong_FromLong((long) st.f_flag));
PyStructSequence_SET_ITEM(v, 9, PyLong_FromLong((long) st.f_namemax));
SET_RESULT(PyLong_FromLong((long) st.f_bsize));
SET_RESULT(PyLong_FromLong((long) st.f_frsize));
Comment on lines +12997 to +12998
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that some code is the same in both branches.

Also, on Linux some of fields are defined as unsigned long instead of long. Did not check other Posix systems. There may be a problem, but this is another issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I found this:

struct statvfs {
               unsigned long  f_bsize;    /* Filesystem block size */
               unsigned long  f_frsize;   /* Fragment size */
               fsblkcnt_t     f_blocks;   /* Size of fs in f_frsize units */
               fsblkcnt_t     f_bfree;    /* Number of free blocks */
               fsblkcnt_t     f_bavail;   /* Number of free blocks for
                                             unprivileged users */
               fsfilcnt_t     f_files;    /* Number of inodes */
               fsfilcnt_t     f_ffree;    /* Number of free inodes */
               fsfilcnt_t     f_favail;   /* Number of free inodes for
                                             unprivileged users */
               unsigned long  f_fsid;     /* Filesystem ID */
               unsigned long  f_flag;     /* Mount flags */
               unsigned long  f_namemax;  /* Maximum filename length */
           };

My proposal:

  • Let's keep this PR focused on a new error handling
  • I will open a new issue about this and do more research: why is it like this
  • Probably I will send a second PR fixing the type

Since posixmodule is rather hard, I would prefer not to do any semantic changes now.

SET_RESULT(PyLong_FromLongLong((long long) st.f_blocks));
SET_RESULT(PyLong_FromLongLong((long long) st.f_bfree));
SET_RESULT(PyLong_FromLongLong((long long) st.f_bavail));
SET_RESULT(PyLong_FromLongLong((long long) st.f_files));
SET_RESULT(PyLong_FromLongLong((long long) st.f_ffree));
SET_RESULT(PyLong_FromLongLong((long long) st.f_favail));
SET_RESULT(PyLong_FromLong((long) st.f_flag));
SET_RESULT(PyLong_FromLong((long) st.f_namemax));
#endif
/* The _ALL_SOURCE feature test macro defines f_fsid as a structure
* (issue #32390). */
#if defined(_AIX) && defined(_ALL_SOURCE)
PyStructSequence_SET_ITEM(v, 10, PyLong_FromUnsignedLong(st.f_fsid.val[0]));
SET_RESULT(PyLong_FromUnsignedLong(st.f_fsid.val[0]));
#else
PyStructSequence_SET_ITEM(v, 10, PyLong_FromUnsignedLong(st.f_fsid));
SET_RESULT(PyLong_FromUnsignedLong(st.f_fsid));
#endif
if (PyErr_Occurred()) {
Py_DECREF(v);
return NULL;
}

#undef SET_RESULT

return v;
}
Expand Down