1 //===-- runtime/io-error.cpp ----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
12 #include "flang/Runtime/magic-numbers.h"
18 namespace Fortran::runtime::io
{
19 RT_OFFLOAD_API_GROUP_BEGIN
21 void IoErrorHandler::SignalError(int iostatOrErrno
, const char *msg
, ...) {
22 // Note that IOMSG= alone without IOSTAT=/END=/EOR=/ERR= does not suffice
23 // for error recovery (see F'2018 subclause 12.11).
24 switch (iostatOrErrno
) {
28 if (flags_
& (hasIoStat
| hasEnd
)) {
29 if (ioStat_
== IostatOk
|| ioStat_
< IostatEnd
) {
36 if (flags_
& (hasIoStat
| hasEor
)) {
37 if (ioStat_
== IostatOk
|| ioStat_
< IostatEor
) {
38 ioStat_
= IostatEor
; // least priority
44 if (flags_
& (hasIoStat
| hasErr
)) {
46 ioStat_
= iostatOrErrno
; // priority over END=/EOR=
47 if (msg
&& (flags_
& hasIoMsg
)) {
48 #if !defined(RT_DEVICE_COMPILATION)
52 std::vsnprintf(buffer
, sizeof buffer
, msg
, ap
);
55 const char *buffer
= "not implemented yet: IOSTAT with varargs";
57 ioMsg_
= SaveDefaultCharacter(
58 buffer
, Fortran::runtime::strlen(buffer
) + 1, *this);
65 // I/O error not caught!
67 #if !defined(RT_DEVICE_COMPILATION)
73 Crash("not implemented yet: IOSTAT with varargs");
75 } else if (const char *errstr
{IostatErrorString(iostatOrErrno
)}) {
78 #if !defined(RT_DEVICE_COMPILATION)
79 Crash("I/O error (errno=%d): %s", iostatOrErrno
,
80 std::strerror(iostatOrErrno
));
82 Crash("I/O error (errno=%d)", iostatOrErrno
);
87 void IoErrorHandler::SignalError(int iostatOrErrno
) {
88 SignalError(iostatOrErrno
, nullptr);
91 void IoErrorHandler::Forward(
92 int ioStatOrErrno
, const char *msg
, std::size_t length
) {
93 if (ioStatOrErrno
!= IostatOk
) {
95 SignalError(ioStatOrErrno
, "%.*s", static_cast<int>(length
), msg
);
97 SignalError(ioStatOrErrno
);
102 void IoErrorHandler::SignalEnd() { SignalError(IostatEnd
); }
104 void IoErrorHandler::SignalEor() { SignalError(IostatEor
); }
106 void IoErrorHandler::SignalPendingError() {
107 int error
{pendingError_
};
108 pendingError_
= IostatOk
;
112 void IoErrorHandler::SignalErrno() { SignalError(errno
); }
114 bool IoErrorHandler::GetIoMsg(char *buffer
, std::size_t bufferLength
) {
115 const char *msg
{ioMsg_
.get()};
117 msg
= IostatErrorString(ioStat_
== IostatOk
? pendingError_
: ioStat_
);
120 ToFortranDefaultCharacter(buffer
, bufferLength
, msg
);
124 // Following code is taken from llvm/lib/Support/Errno.cpp
125 // in LLVM v9.0.1 with inadequate modification for Fortran,
128 #if defined(RT_DEVICE_COMPILATION)
129 // strerror_r is not available on device.
130 msg
= "errno description is not available on device";
131 #elif HAVE_STRERROR_R
132 // strerror_r is thread-safe.
133 #if defined(__GLIBC__) && defined(_GNU_SOURCE)
134 // glibc defines its own incompatible version of strerror_r
135 // which may not use the buffer supplied.
136 msg
= ::strerror_r(ioStat_
, buffer
, bufferLength
);
138 ok
= ::strerror_r(ioStat_
, buffer
, bufferLength
) == 0;
140 #elif HAVE_DECL_STRERROR_S // "Windows Secure API"
141 ok
= ::strerror_s(buffer
, bufferLength
, ioStat_
) == 0;
143 // Copy the thread un-safe result of strerror into
144 // the buffer as fast as possible to minimize impact
145 // of collision of strerror in multiple threads.
146 msg
= strerror(ioStat_
);
149 ToFortranDefaultCharacter(buffer
, bufferLength
, msg
);
152 std::size_t copied
{Fortran::runtime::strlen(buffer
)};
153 if (copied
< bufferLength
) {
154 std::memset(buffer
+ copied
, ' ', bufferLength
- copied
);
162 RT_OFFLOAD_API_GROUP_END
163 } // namespace Fortran::runtime::io