-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc] Add the implementation of the fdopen function #94186
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
Conversation
@llvm/pr-subscribers-libc Author: Xu Zhang (simonzgx) ChangesFull diff: https://github.com/llvm/llvm-project/pull/94186.diff 9 Files Affected:
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index ca0418c3618ae..81d14271547dc 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -201,6 +201,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.snprintf
libc.src.stdio.vsprintf
libc.src.stdio.vsnprintf
+ libc.src.stdio.fdopen
#libc.src.stdio.sscanf
#libc.src.stdio.scanf
#libc.src.stdio.fscanf
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 479af40b5b26b..fc5300f9be2d0 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -209,6 +209,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.sscanf
libc.src.stdio.scanf
libc.src.stdio.fscanf
+ libc.src.stdio.fdopen
# sys/mman.h entrypoints
libc.src.sys.mman.madvise
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 699bb9dcdf3c9..082dfe7ac5f73 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -214,6 +214,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdio.scanf
libc.src.stdio.fscanf
libc.src.stdio.fileno
+ libc.src.stdio.fdopen
# sys/epoll.h entrypoints
libc.src.sys.epoll.epoll_create
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index e16353b8142de..78d9d727ac7b4 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -1293,6 +1293,11 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<FILEPtr>]
>,
+ FunctionSpec<
+ "fdopen",
+ RetValSpec<FILEPtr>,
+ [ArgSpec<IntType>, ArgSpec<ConstCharPtr>]
+ >,
]
>;
diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt
index 1056f38fc7513..deb7e5ad942bf 100644
--- a/libc/src/stdio/CMakeLists.txt
+++ b/libc/src/stdio/CMakeLists.txt
@@ -263,6 +263,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.rename
)
+add_entrypoint_object(
+ fdopen
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.fdopen
+)
+
# These entrypoints have multiple potential implementations.
add_stdio_entrypoint_object(feof)
add_stdio_entrypoint_object(feof_unlocked)
diff --git a/libc/src/stdio/fdopen.h b/libc/src/stdio/fdopen.h
new file mode 100644
index 0000000000000..158a133e7e131
--- /dev/null
+++ b/libc/src/stdio/fdopen.h
@@ -0,0 +1,20 @@
+//===-- Implementation header of open ---------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDIO_FDOPEN_H
+#define LLVM_LIBC_SRC_STDIO_FDOPEN_H
+
+#include <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+FILE *fdopen(int fd, const char *mode);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDIO_FDOPEN_H
diff --git a/libc/src/stdio/linux/CMakeLists.txt b/libc/src/stdio/linux/CMakeLists.txt
index a08ff0ba4832f..133740fcb41f4 100644
--- a/libc/src/stdio/linux/CMakeLists.txt
+++ b/libc/src/stdio/linux/CMakeLists.txt
@@ -24,3 +24,17 @@ add_entrypoint_object(
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ fdopen
+ SRCS
+ fdopen.cpp
+ HDRS
+ ../fdopen.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.stdio
+ libc.src.errno.errno
+ libc.src.fcntl.fcntl
+ libc.src.stdio.fseek
+)
\ No newline at end of file
diff --git a/libc/src/stdio/linux/fdopen.cpp b/libc/src/stdio/linux/fdopen.cpp
new file mode 100644
index 0000000000000..91b27a568b0e1
--- /dev/null
+++ b/libc/src/stdio/linux/fdopen.cpp
@@ -0,0 +1,79 @@
+//===-- Implementation of fprintf -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/stdio/fdopen.h"
+
+#include "include/llvm-libc-macros/generic-error-number-macros.h"
+#include "include/llvm-libc-macros/linux/fcntl-macros.h"
+#include "src/__support/File/linux/file.h"
+#include "src/errno/libc_errno.h"
+#include "src/fcntl/fcntl.h"
+#include "src/stdio/fseek.h"
+
+#include <stdio.h>
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(::FILE *, fdopen, (int fd, const char *mode)) {
+ auto modeflags = LIBC_NAMESPACE::File::mode_flags(mode);
+ if (modeflags == 0) {
+ libc_errno = EINVAL;
+ return nullptr;
+ }
+
+ int fd_flags = LIBC_NAMESPACE::fcntl(fd, F_GETFL);
+ if (fd_flags == -1) {
+ libc_errno = EBADF;
+ return nullptr;
+ }
+
+ using OpenMode = File::OpenMode;
+ if (((fd_flags & O_ACCMODE) == O_RDONLY &&
+ !(modeflags & static_cast<ModeFlags>(OpenMode::READ))) ||
+ ((fd_flags & O_ACCMODE) == O_WRONLY &&
+ !(modeflags & static_cast<ModeFlags>(OpenMode::WRITE)))) {
+ libc_errno = EINVAL;
+ return nullptr;
+ }
+
+ bool do_seek = false;
+ if ((modeflags & static_cast<File::ModeFlags>(File::OpenMode::APPEND)) &&
+ !(fd_flags & O_APPEND)) {
+ do_seek = true;
+ if (LIBC_NAMESPACE::fcntl(fd, F_SETFL, fd_flags | O_APPEND) == -1) {
+ libc_errno = EBADF;
+ return nullptr;
+ }
+ }
+
+ uint8_t *buffer;
+ {
+ AllocChecker ac;
+ buffer = new (ac) uint8_t[File::DEFAULT_BUFFER_SIZE];
+ if (!ac) {
+ libc_errno = ENOMEM;
+ return nullptr;
+ }
+ }
+ AllocChecker ac;
+ auto *linux_file = new (ac)
+ LinuxFile(fd, buffer, File::DEFAULT_BUFFER_SIZE, _IOFBF, true, modeflags);
+ if (!ac) {
+ libc_errno = ENOMEM;
+ return nullptr;
+ }
+ auto *file = reinterpret_cast<::FILE *>(linux_file);
+ if (do_seek && LIBC_NAMESPACE::fseek(file, 0, SEEK_END) != 0) {
+ free(linux_file);
+ return nullptr;
+ }
+
+ return file;
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/test/src/stdio/fdopen_test.cpp b/libc/test/src/stdio/fdopen_test.cpp
new file mode 100644
index 0000000000000..e69de29bb2d1d
|
ac070ea
to
6460fba
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
c5550a8
to
e06d269
Compare
e06d269
to
a926d0f
Compare
This PR is ready to be reviewed, please hava a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a good start, but needs some tweaks before landing
#ifndef LLVM_LIBC_SRC_STDIO_FDOPEN_H | ||
#define LLVM_LIBC_SRC_STDIO_FDOPEN_H | ||
|
||
#include <stdio.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michaelrj-google : shall we create an issue to add proxy header for FILE
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good, just a few nits and organizational comments left
63cc961
to
8203762
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
almost done, just one last change and I think this will be good to land
libc/src/__support/File/file.h
Outdated
ErrorOr<File *> openfile(const char *path, const char *mode); | ||
// Create a File object and associate it with a fd. | ||
ErrorOr<File *> create_file_from_fd(int fd, const char *mode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this shouldn't be in the top level file.h
since it's linux specific. It should be in the linux specific file.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If so, I hava to include linux/file.h
in fdopen.cpp
, is that OK?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes that's fine. Given that this is a linux specific implementation of fdopen I'm okay with it directly including the linux specific file.
07c2329
to
0f7bdf2
Compare
ping |
if (retVal == -EINVAL) | ||
return LIBC_NAMESPACE::syscall_impl<int>(SYS_fcntl, fd, cmd, | ||
reinterpret_cast<void *>(arg)); | ||
if (static_cast<unsigned long>(retVal) <= -4096UL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-4096UL
while left hand side is unsigned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Michael seems to have asked the same question, see #89507
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused by this logic. If the return result is negative but malformed, should we return errors instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also we should use MAX_ERRNO
instead of hard-coded value here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm confused by this logic. If the return result is negative but malformed, should we return errors instead?
Frankly, I'm also puzzled by this code. I found the same code in GLIBC, yet I'm also uncertain as to why the GLIBC's authors chose this way. Perhaps we could set it aside for now, and I'll open a new issue to address it after I delve into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're only moving the function to different location, it's fine for me to leave it as-is. But please create an issue for further investigation / fixing and add a TODO here. Thanks,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're only moving the function to different location, it's fine for me to leave it as-is. But please create an issue for further investigation / fixing and add a TODO here. Thanks,
Please help assign #95570 to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We really should not be copying code from ANY libc which we do not understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@michaelrj-google Could you help merge this patch? Thanks. |
Merged. Thanks for the patch! |
@@ -8,11 +8,17 @@ add_object_library( | |||
linux_util | |||
SRCS | |||
exit.cpp | |||
fcntl.cpp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fcntl
should be a separate target.
flk->l_start = flk64.l_start; | ||
flk->l_len = flk64.l_len; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this patch. Note though that it did break the 32b ARM build bot:
https://lab.llvm.org/buildbot/#/builders/182/builds/54
/llvm/libc_worker/worker/libc-arm32-debian/libc-arm32-debian-dbg/llvm-project/libc/src/__support/OSUtil/linux/fcntl.cpp:63:26: error: implicit conversion loses integer precision: '__off64_t' (aka 'long long') to '__off_t' (aka 'long') [-Werror,-Wshorten-64-to-32]
flk->l_start = flk64.l_start;
~ ~~~~~~^~~~~~~
/llvm/libc_worker/worker/libc-arm32-debian/libc-arm32-debian-dbg/llvm-project/libc/src/__support/OSUtil/linux/fcntl.cpp:64:24: error: implicit conversion loses integer precision: '__off64_t' (aka 'long long') to '__off_t' (aka 'long') [-Werror,-Wshorten-64-to-32]
flk->l_len = flk64.l_len;
~ ~~~~~~^~~~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixes #93711 .
This patch implements the
fdopen
function. Given thatfdopen
internally calls
fcntl
, the implementation offcntl
has beenmoved to the
__support/OSUtil
, where it serves as an internal publicfunction.