Skip to content

Commit 9beb8d1

Browse files
[libc] move errno out of file internals
Now errno is only set by the terminal entrypoints, and not the internal implementations. This patch is part of the larger effort to not set errno in libc internal code: llvm#59278 Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D139576
1 parent 93bbcff commit 9beb8d1

39 files changed

+514
-283
lines changed

libc/src/__support/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ add_header_library(
3030
sanitizer.h
3131
)
3232

33+
add_header_library(
34+
error_or
35+
HDRS
36+
error_or.h
37+
DEPENDS
38+
libc.src.__support.CPP.expected
39+
)
40+
3341
add_header_library(
3442
ctype_utils
3543
HDRS

libc/src/__support/CPP/CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ add_header_library(
9494
)
9595

9696
add_header_library(
97-
error
97+
expected
9898
HDRS
99-
error.h
99+
expected.h
100100
)

libc/src/__support/CPP/error.h

Lines changed: 0 additions & 51 deletions
This file was deleted.

libc/src/__support/CPP/expected.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//===-- Holds an expected or unexpected value -------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SUPPORT_CPP_EXPECTED_H
10+
#define LLVM_LIBC_SUPPORT_CPP_EXPECTED_H
11+
12+
namespace __llvm_libc::cpp {
13+
14+
// This is used to hold an unexpected value so that a different constructor is
15+
// selected.
16+
template <class T> class unexpected {
17+
T value;
18+
19+
public:
20+
constexpr explicit unexpected(T value) : value(value) {}
21+
constexpr T error() { return value; }
22+
};
23+
24+
template <class T, class E> class expected {
25+
union {
26+
T exp;
27+
E unexp;
28+
};
29+
bool is_expected;
30+
31+
public:
32+
constexpr expected(T exp) : exp(exp), is_expected(true) {}
33+
constexpr expected(unexpected<E> unexp)
34+
: unexp(unexp.error()), is_expected(false) {}
35+
36+
constexpr bool has_value() { return is_expected; }
37+
38+
constexpr T value() { return exp; }
39+
constexpr E error() { return unexp; }
40+
41+
constexpr operator T() { return exp; }
42+
constexpr operator bool() { return is_expected; }
43+
44+
constexpr T &operator*() { return exp; }
45+
constexpr const T &operator*() const { return exp; }
46+
constexpr T *operator->() { return &exp; }
47+
constexpr const T *operator->() const { return &exp; }
48+
};
49+
50+
} // namespace __llvm_libc::cpp
51+
52+
#endif // LLVM_LIBC_SUPPORT_CPP_EXPECTED_H

libc/src/__support/File/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ add_object_library(
1414
libc.include.errno
1515
libc.src.__support.CPP.span
1616
libc.src.__support.threads.mutex
17-
libc.src.errno.errno
17+
libc.src.__support.error_or
1818
)
1919

2020
add_object_library(
@@ -41,6 +41,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS}_file.cpp)
4141
libc.include.sys_syscall
4242
libc.src.__support.OSUtil.osutil
4343
libc.src.errno.errno
44+
libc.src.__support.error_or
4445
)
4546
endif()
4647

libc/src/__support/File/file.cpp

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@
1010

1111
#include "src/__support/CPP/span.h"
1212

13-
#include <errno.h>
13+
#include <errno.h> // For error macros
1414
#include <stdio.h>
1515
#include <stdlib.h>
1616

1717
namespace __llvm_libc {
1818

19-
size_t File::write_unlocked(const void *data, size_t len) {
19+
FileIOResult File::write_unlocked(const void *data, size_t len) {
2020
if (!write_allowed()) {
21-
errno = EBADF;
2221
err = true;
23-
return 0;
22+
return {0, EBADF};
2423
}
2524

2625
prev_op = FileOp::WRITE;
@@ -37,26 +36,27 @@ size_t File::write_unlocked(const void *data, size_t len) {
3736
}
3837
}
3938

40-
size_t File::write_unlocked_nbf(const uint8_t *data, size_t len) {
39+
FileIOResult File::write_unlocked_nbf(const uint8_t *data, size_t len) {
4140
if (pos > 0) { // If the buffer is not empty
4241
// Flush the buffer
4342
const size_t write_size = pos;
44-
size_t bytes_written = platform_write(this, buf, write_size);
43+
auto write_result = platform_write(this, buf, write_size);
4544
pos = 0; // Buffer is now empty so reset pos to the beginning.
4645
// If less bytes were written than expected, then an error occurred.
47-
if (bytes_written < write_size) {
46+
if (write_result < write_size) {
4847
err = true;
49-
return 0; // No bytes from data were written, so return 0.
48+
// No bytes from data were written, so return 0.
49+
return {0, write_result.error};
5050
}
5151
}
5252

53-
size_t written = platform_write(this, data, len);
54-
if (written < len)
53+
auto write_result = platform_write(this, data, len);
54+
if (write_result < len)
5555
err = true;
56-
return written;
56+
return write_result;
5757
}
5858

59-
size_t File::write_unlocked_fbf(const uint8_t *data, size_t len) {
59+
FileIOResult File::write_unlocked_fbf(const uint8_t *data, size_t len) {
6060
const size_t init_pos = pos;
6161
const size_t bufspace = bufsize - pos;
6262

@@ -96,13 +96,17 @@ size_t File::write_unlocked_fbf(const uint8_t *data, size_t len) {
9696
// We need to flush the buffer now, since there is still data and the buffer
9797
// is full.
9898
const size_t write_size = pos;
99-
size_t bytes_written = platform_write(this, buf, write_size);
99+
100+
auto buf_result = platform_write(this, buf, write_size);
101+
size_t bytes_written = buf_result.value;
102+
100103
pos = 0; // Buffer is now empty so reset pos to the beginning.
101104
// If less bytes were written than expected, then an error occurred. Return
102105
// the number of bytes that have been written from |data|.
103-
if (bytes_written < write_size) {
106+
if (buf_result.has_error() || bytes_written < write_size) {
104107
err = true;
105-
return bytes_written <= init_pos ? 0 : bytes_written - init_pos;
108+
return {bytes_written <= init_pos ? 0 : bytes_written - init_pos,
109+
buf_result.error};
106110
}
107111

108112
// The second piece is handled basically the same as the first, although we
@@ -114,21 +118,22 @@ size_t File::write_unlocked_fbf(const uint8_t *data, size_t len) {
114118
bufref[i] = remainder[i];
115119
pos = remainder.size();
116120
} else {
117-
size_t bytes_written =
118-
platform_write(this, remainder.data(), remainder.size());
121+
122+
auto result = platform_write(this, remainder.data(), remainder.size());
123+
size_t bytes_written = buf_result.value;
119124

120125
// If less bytes were written than expected, then an error occurred. Return
121126
// the number of bytes that have been written from |data|.
122-
if (bytes_written < remainder.size()) {
127+
if (result.has_error() || bytes_written < remainder.size()) {
123128
err = true;
124-
return primary.size() + bytes_written;
129+
return {primary.size() + bytes_written, result.error};
125130
}
126131
}
127132

128133
return len;
129134
}
130135

131-
size_t File::write_unlocked_lbf(const uint8_t *data, size_t len) {
136+
FileIOResult File::write_unlocked_lbf(const uint8_t *data, size_t len) {
132137
constexpr uint8_t NEWLINE_CHAR = '\n';
133138
size_t last_newline = len;
134139
for (size_t i = len; i >= 1; --i) {
@@ -175,11 +180,10 @@ size_t File::write_unlocked_lbf(const uint8_t *data, size_t len) {
175180
return len;
176181
}
177182

178-
size_t File::read_unlocked(void *data, size_t len) {
183+
FileIOResult File::read_unlocked(void *data, size_t len) {
179184
if (!read_allowed()) {
180-
errno = EBADF;
181185
err = true;
182-
return 0;
186+
return {0, EBADF};
183187
}
184188

185189
prev_op = FileOp::READ;
@@ -210,31 +214,33 @@ size_t File::read_unlocked(void *data, size_t len) {
210214

211215
size_t to_fetch = len - available_data;
212216
if (to_fetch > bufsize) {
213-
size_t fetched_size = platform_read(this, dataref.data(), to_fetch);
214-
if (fetched_size < to_fetch) {
215-
if (errno == 0)
217+
auto result = platform_read(this, dataref.data(), to_fetch);
218+
size_t fetched_size = result.value;
219+
if (result.has_error() || fetched_size < to_fetch) {
220+
if (!result.has_error())
216221
eof = true;
217222
else
218223
err = true;
219-
return available_data + fetched_size;
224+
return {available_data + fetched_size, result.has_error()};
220225
}
221226
return len;
222227
}
223228

224229
// Fetch and buffer another buffer worth of data.
225-
size_t fetched_size = platform_read(this, buf, bufsize);
230+
auto result = platform_read(this, buf, bufsize);
231+
size_t fetched_size = result.value;
226232
read_limit += fetched_size;
227233
size_t transfer_size = fetched_size >= to_fetch ? to_fetch : fetched_size;
228234
for (size_t i = 0; i < transfer_size; ++i)
229235
dataref[i] = bufref[i];
230236
pos += transfer_size;
231-
if (fetched_size < to_fetch) {
232-
if (errno == 0)
237+
if (result.has_error() || fetched_size < to_fetch) {
238+
if (!result.has_error())
233239
eof = true;
234240
else
235241
err = true;
236242
}
237-
return transfer_size + available_data;
243+
return {transfer_size + available_data, result.error};
238244
}
239245

240246
int File::ungetc_unlocked(int c) {
@@ -275,13 +281,14 @@ int File::ungetc_unlocked(int c) {
275281
return c;
276282
}
277283

278-
int File::seek(long offset, int whence) {
284+
ErrorOr<int> File::seek(long offset, int whence) {
279285
FileLock lock(this);
280286
if (prev_op == FileOp::WRITE && pos > 0) {
281-
size_t transferred_size = platform_write(this, buf, pos);
282-
if (transferred_size < pos) {
287+
288+
auto buf_result = platform_write(this, buf, pos);
289+
if (buf_result.has_error() || buf_result.value < pos) {
283290
err = true;
284-
return -1;
291+
return Error(buf_result.error);
285292
}
286293
} else if (prev_op == FileOp::READ && whence == SEEK_CUR) {
287294
// More data could have been read out from the platform file than was
@@ -294,22 +301,20 @@ int File::seek(long offset, int whence) {
294301
// Reset the eof flag as a seek might move the file positon to some place
295302
// readable.
296303
eof = false;
297-
long platform_pos = platform_seek(this, offset, whence);
298-
if (platform_pos >= 0)
299-
return 0;
304+
auto result = platform_seek(this, offset, whence);
305+
if (!result.has_value())
306+
return Error(result.error());
300307
else
301-
return -1;
308+
return 0;
302309
}
303310

304-
long File::tell() {
311+
ErrorOr<long> File::tell() {
305312
FileLock lock(this);
306-
long platform_offset;
307-
if (eof)
308-
platform_offset = platform_seek(this, 0, SEEK_END);
309-
else
310-
platform_offset = platform_seek(this, 0, SEEK_CUR);
311-
if (platform_offset < 0)
312-
return -1;
313+
auto seek_target = eof ? SEEK_END : SEEK_CUR;
314+
auto result = platform_seek(this, 0, seek_target);
315+
if (!result.has_value() || result.value() < 0)
316+
return Error(result.error());
317+
long platform_offset = result.value();
313318
if (prev_op == FileOp::READ)
314319
return platform_offset - (read_limit - pos);
315320
else if (prev_op == FileOp::WRITE)
@@ -320,10 +325,10 @@ long File::tell() {
320325

321326
int File::flush_unlocked() {
322327
if (prev_op == FileOp::WRITE && pos > 0) {
323-
size_t transferred_size = platform_write(this, buf, pos);
324-
if (transferred_size < pos) {
328+
auto buf_result = platform_write(this, buf, pos);
329+
if (buf_result.has_error() || buf_result.value < pos) {
325330
err = true;
326-
return -1;
331+
return buf_result.error;
327332
}
328333
pos = 0;
329334
return platform_flush(this);
@@ -336,14 +341,15 @@ int File::close() {
336341
{
337342
FileLock lock(this);
338343
if (prev_op == FileOp::WRITE && pos > 0) {
339-
size_t transferred_size = platform_write(this, buf, pos);
340-
if (transferred_size < pos) {
344+
auto buf_result = platform_write(this, buf, pos);
345+
if (buf_result.has_error() || buf_result.value < pos) {
341346
err = true;
342-
return -1;
347+
return buf_result.error;
343348
}
344349
}
345-
if (platform_close(this) != 0)
346-
return -1;
350+
int result = platform_close(this);
351+
if (result != 0)
352+
return result;
347353
if (own_buf)
348354
free(buf);
349355
}

0 commit comments

Comments
 (0)