Skip to content

Commit 824b220

Browse files
[libc][NFC] Adjust use of off_t internally
This patch includes changes to the use of off_t in libc, targeted at 32-bit systems: in several places, the offset is used either as a long or an off_t (64-bit signed int), but in 32-bit systems a long type is only 32 bits long. 1. Fix a warning in mmap where a long offset is expected, but we were passing an off_t. A static_cast and a comment were added to explain that we know we are ignoring the upper 32-bit of the off_t in 32-bit systems. 2. The code in pread and pwrite was slightly improved to remove a #ifdef LIBC_TARGET_ARCH_IS_RISCV32; we are using an if constexpr now. 3. The Linux file operations were changed to use off_t instead of a long where applicable. No changes were made to the standard API, e.g., ftell returns the offset as an int so we added a static_cast and a comment explaining that this will cause a loss of integer precision in 32-bit systems.
1 parent 4f77677 commit 824b220

File tree

10 files changed

+58
-39
lines changed

10 files changed

+58
-39
lines changed

libc/src/__support/File/file.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -305,23 +305,21 @@ ErrorOr<int> File::seek(long offset, int whence) {
305305
auto result = platform_seek(this, offset, whence);
306306
if (!result.has_value())
307307
return Error(result.error());
308-
else
309-
return 0;
308+
return 0;
310309
}
311310

312-
ErrorOr<long> File::tell() {
311+
ErrorOr<off_t> File::tell() {
313312
FileLock lock(this);
314313
auto seek_target = eof ? SEEK_END : SEEK_CUR;
315314
auto result = platform_seek(this, 0, seek_target);
316315
if (!result.has_value() || result.value() < 0)
317316
return Error(result.error());
318-
long platform_offset = result.value();
317+
off_t platform_offset = result.value();
319318
if (prev_op == FileOp::READ)
320319
return platform_offset - (read_limit - pos);
321-
else if (prev_op == FileOp::WRITE)
320+
if (prev_op == FileOp::WRITE)
322321
return platform_offset + pos;
323-
else
324-
return platform_offset;
322+
return platform_offset;
325323
}
326324

327325
int File::flush_unlocked() {

libc/src/__support/File/file.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <stddef.h>
1818
#include <stdint.h>
19+
#include <unistd.h> // For off_t.
1920

2021
namespace LIBC_NAMESPACE {
2122

@@ -45,7 +46,7 @@ class File {
4546
using ReadFunc = FileIOResult(File *, void *, size_t);
4647
// The SeekFunc is expected to return the current offset of the external
4748
// file position indicator.
48-
using SeekFunc = ErrorOr<long>(File *, long, int);
49+
using SeekFunc = ErrorOr<off_t>(File *, off_t, int);
4950
using CloseFunc = int(File *);
5051

5152
using ModeFlags = uint32_t;
@@ -182,7 +183,7 @@ class File {
182183

183184
ErrorOr<int> seek(long offset, int whence);
184185

185-
ErrorOr<long> tell();
186+
ErrorOr<off_t> tell();
186187

187188
// If buffer has data written to it, flush it out. Does nothing if the
188189
// buffer is currently being used as a read buffer.

libc/src/__support/File/linux/file.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ FileIOResult linux_file_read(File *f, void *buf, size_t size) {
4242
return ret;
4343
}
4444

45-
ErrorOr<long> linux_file_seek(File *f, long offset, int whence) {
45+
ErrorOr<off_t> linux_file_seek(File *f, off_t offset, int whence) {
4646
auto *lf = reinterpret_cast<LinuxFile *>(f);
4747
auto result = internal::lseekimpl(lf->get_fd(), offset, whence);
4848
if (!result.has_value())

libc/src/__support/File/linux/file.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace LIBC_NAMESPACE {
1212

1313
FileIOResult linux_file_write(File *, const void *, size_t);
1414
FileIOResult linux_file_read(File *, void *, size_t);
15-
ErrorOr<long> linux_file_seek(File *, long, int);
15+
ErrorOr<off_t> linux_file_seek(File *, off_t, int);
1616
int linux_file_close(File *);
1717

1818
class LinuxFile : public File {

libc/src/stdio/fopencookie.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class CookieFile : public LIBC_NAMESPACE::File {
2424

2525
static FileIOResult cookie_write(File *f, const void *data, size_t size);
2626
static FileIOResult cookie_read(File *f, void *data, size_t size);
27-
static ErrorOr<long> cookie_seek(File *f, long offset, int whence);
27+
static ErrorOr<off_t> cookie_seek(File *f, off_t offset, int whence);
2828
static int cookie_close(File *f);
2929

3030
public:
@@ -52,7 +52,7 @@ FileIOResult CookieFile::cookie_read(File *f, void *data, size_t size) {
5252
reinterpret_cast<char *>(data), size);
5353
}
5454

55-
ErrorOr<long> CookieFile::cookie_seek(File *f, long offset, int whence) {
55+
ErrorOr<off_t> CookieFile::cookie_seek(File *f, off_t offset, int whence) {
5656
auto cookie_file = reinterpret_cast<CookieFile *>(f);
5757
if (cookie_file->ops.seek == nullptr) {
5858
return Error(EINVAL);
@@ -61,8 +61,7 @@ ErrorOr<long> CookieFile::cookie_seek(File *f, long offset, int whence) {
6161
int result = cookie_file->ops.seek(cookie_file->cookie, &offset64, whence);
6262
if (result == 0)
6363
return offset64;
64-
else
65-
return -1;
64+
return -1;
6665
}
6766

6867
int CookieFile::cookie_close(File *f) {

libc/src/stdio/generic/ftell.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ LLVM_LIBC_FUNCTION(long, ftell, (::FILE * stream)) {
1919
libc_errno = result.error();
2020
return -1;
2121
}
22-
return result.value();
22+
// tell() returns an off_t (64-bit signed integer), but this function returns
23+
// a long (32-bit signed integer in 32-bit systems). We add a cast here to
24+
// silence a "implicit conversion loses integer precision" warning when
25+
// compiling for 32-bit systems.
26+
return static_cast<long>(result.value());
2327
}
2428

2529
} // namespace LIBC_NAMESPACE

libc/src/sys/mman/linux/mmap.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,12 @@ LLVM_LIBC_FUNCTION(void *, mmap,
3939
#error "mmap or mmap2 syscalls not available."
4040
#endif
4141

42+
// We add an explicit cast to silence a "implicit conversion loses integer
43+
// precision" warning when compiling for 32-bit systems.
44+
long mmap_offset = static_cast<long>(offset);
4245
long ret =
4346
LIBC_NAMESPACE::syscall_impl(syscall_number, reinterpret_cast<long>(addr),
44-
size, prot, flags, fd, offset);
47+
size, prot, flags, fd, mmap_offset);
4548

4649
// The mmap/mmap2 syscalls return negative values on error. These negative
4750
// values are actually the negative values of the error codes. So, fix them

libc/src/unistd/linux/pread.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,21 @@ namespace LIBC_NAMESPACE {
1919

2020
LLVM_LIBC_FUNCTION(ssize_t, pread,
2121
(int fd, void *buf, size_t count, off_t offset)) {
22-
#ifdef LIBC_TARGET_ARCH_IS_RISCV32
23-
static_assert(sizeof(off_t) == 8);
24-
ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(
25-
SYS_pread64, fd, buf, count, (long)offset,
26-
(long)(((uint64_t)(offset)) >> 32));
27-
#else
28-
ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pread64, fd, buf,
29-
count, offset);
30-
#endif
22+
ssize_t ret;
23+
if constexpr (sizeof(long) == sizeof(uint32_t) &&
24+
sizeof(off_t) == sizeof(uint64_t)) {
25+
// This is a 32-bit system with a 64-bit offset, offset must be split.
26+
const uint64_t bits = cpp::bit_cast<uint64_t>(offset);
27+
const uint32_t lo = bits & UINT32_MAX;
28+
const uint32_t hi = bits >> 32;
29+
const long offset_low = cpp::bit_cast<long>(static_cast<long>(lo));
30+
const long offset_high = cpp::bit_cast<long>(static_cast<long>(hi));
31+
ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pread64, fd, buf, count,
32+
offset_low, offset_high);
33+
} else {
34+
ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pread64, fd, buf, count,
35+
offset);
36+
}
3137
// The cast is important since there is a check that dereferences the pointer
3238
// which fails on void*.
3339
MSAN_UNPOISON(reinterpret_cast<char *>(buf), count);

libc/src/unistd/linux/pwrite.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,23 @@ namespace LIBC_NAMESPACE {
1919

2020
LLVM_LIBC_FUNCTION(ssize_t, pwrite,
2121
(int fd, const void *buf, size_t count, off_t offset)) {
22-
#ifdef LIBC_TARGET_ARCH_IS_RISCV32
23-
static_assert(sizeof(off_t) == 8);
24-
ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(
25-
SYS_pwrite64, fd, buf, count, (long)offset,
26-
(long)(((uint64_t)(offset)) >> 32));
27-
#else
28-
ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pwrite64, fd, buf,
29-
count, offset);
30-
#endif
22+
23+
ssize_t ret;
24+
if constexpr (sizeof(long) == sizeof(uint32_t) &&
25+
sizeof(off_t) == sizeof(uint64_t)) {
26+
// This is a 32-bit system with a 64-bit offset, offset must be split.
27+
const uint64_t bits = cpp::bit_cast<uint64_t>(offset);
28+
const uint32_t lo = bits & UINT32_MAX;
29+
const uint32_t hi = bits >> 32;
30+
const long offset_low = cpp::bit_cast<long>(static_cast<long>(lo));
31+
const long offset_high = cpp::bit_cast<long>(static_cast<long>(hi));
32+
ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pwrite64, fd, buf, count,
33+
offset_low, offset_high);
34+
} else {
35+
ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_pwrite64, fd, buf, count,
36+
offset);
37+
}
38+
3139
if (ret < 0) {
3240
libc_errno = static_cast<int>(-ret);
3341
return -1;

libc/test/src/__support/File/file_test.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class StringFile : public File {
3131
static FileIOResult str_read(LIBC_NAMESPACE::File *f, void *data, size_t len);
3232
static FileIOResult str_write(LIBC_NAMESPACE::File *f, const void *data,
3333
size_t len);
34-
static ErrorOr<long> str_seek(LIBC_NAMESPACE::File *f, long offset,
35-
int whence);
34+
static ErrorOr<off_t> str_seek(LIBC_NAMESPACE::File *f, off_t offset,
35+
int whence);
3636
static int str_close(LIBC_NAMESPACE::File *f) {
3737
delete reinterpret_cast<StringFile *>(f);
3838
return 0;
@@ -93,8 +93,8 @@ FileIOResult StringFile::str_write(LIBC_NAMESPACE::File *f, const void *data,
9393
return i;
9494
}
9595

96-
ErrorOr<long> StringFile::str_seek(LIBC_NAMESPACE::File *f, long offset,
97-
int whence) {
96+
ErrorOr<off_t> StringFile::str_seek(LIBC_NAMESPACE::File *f, off_t offset,
97+
int whence) {
9898
StringFile *sf = static_cast<StringFile *>(f);
9999
if (whence == SEEK_SET)
100100
sf->pos = offset;

0 commit comments

Comments
 (0)