1651f58bfSDiana Picus //===-- runtime/io-error.cpp ----------------------------------------------===// 2352d347aSAlexis Perry // 3352d347aSAlexis Perry // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4352d347aSAlexis Perry // See https://llvm.org/LICENSE.txt for license information. 5352d347aSAlexis Perry // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6352d347aSAlexis Perry // 7352d347aSAlexis Perry //===----------------------------------------------------------------------===// 8352d347aSAlexis Perry 9352d347aSAlexis Perry #include "io-error.h" 101f879005STim Keith #include "config.h" 113b635714Speter klausler #include "tools.h" 12830c0b90SPeter Klausler #include "flang/Runtime/magic-numbers.h" 13352d347aSAlexis Perry #include <cerrno> 143b635714Speter klausler #include <cstdarg> 15352d347aSAlexis Perry #include <cstdio> 16352d347aSAlexis Perry #include <cstring> 17352d347aSAlexis Perry 18352d347aSAlexis Perry namespace Fortran::runtime::io { 198ebf7411SSlava Zakharin RT_OFFLOAD_API_GROUP_BEGIN 20352d347aSAlexis Perry 213b635714Speter klausler void IoErrorHandler::SignalError(int iostatOrErrno, const char *msg, ...) { 220a8a572cSPeter Klausler // Note that IOMSG= alone without IOSTAT=/END=/EOR=/ERR= does not suffice 230a8a572cSPeter Klausler // for error recovery (see F'2018 subclause 12.11). 240a8a572cSPeter Klausler switch (iostatOrErrno) { 250a8a572cSPeter Klausler case IostatOk: 260a8a572cSPeter Klausler return; 270a8a572cSPeter Klausler case IostatEnd: 28*bf95854eSPeter Klausler if ((flags_ & (hasIoStat | hasEnd)) || 29*bf95854eSPeter Klausler ((flags_ & hasErr) && (flags_ & hasRec))) { 30*bf95854eSPeter Klausler // EOF goes to ERR= when REC= is present 31e81c96d6Speter klausler if (ioStat_ == IostatOk || ioStat_ < IostatEnd) { 323b635714Speter klausler ioStat_ = IostatEnd; 333b635714Speter klausler } 340a8a572cSPeter Klausler return; 350a8a572cSPeter Klausler } 360a8a572cSPeter Klausler break; 370a8a572cSPeter Klausler case IostatEor: 380a8a572cSPeter Klausler if (flags_ & (hasIoStat | hasEor)) { 39e51939ecSpeter klausler if (ioStat_ == IostatOk || ioStat_ < IostatEor) { 403b635714Speter klausler ioStat_ = IostatEor; // least priority 413b635714Speter klausler } 420a8a572cSPeter Klausler return; 430a8a572cSPeter Klausler } 440a8a572cSPeter Klausler break; 450a8a572cSPeter Klausler default: 460a8a572cSPeter Klausler if (flags_ & (hasIoStat | hasErr)) { 47352d347aSAlexis Perry if (ioStat_ <= 0) { 48352d347aSAlexis Perry ioStat_ = iostatOrErrno; // priority over END=/EOR= 493b635714Speter klausler if (msg && (flags_ & hasIoMsg)) { 508ebf7411SSlava Zakharin #if !defined(RT_DEVICE_COMPILATION) 513b635714Speter klausler char buffer[256]; 523b635714Speter klausler va_list ap; 533b635714Speter klausler va_start(ap, msg); 543b635714Speter klausler std::vsnprintf(buffer, sizeof buffer, msg, ap); 554f41994cSpeter klausler va_end(ap); 568ebf7411SSlava Zakharin #else 578ebf7411SSlava Zakharin const char *buffer = "not implemented yet: IOSTAT with varargs"; 588ebf7411SSlava Zakharin #endif 598ebf7411SSlava Zakharin ioMsg_ = SaveDefaultCharacter( 608ebf7411SSlava Zakharin buffer, Fortran::runtime::strlen(buffer) + 1, *this); 61352d347aSAlexis Perry } 623b635714Speter klausler } 630a8a572cSPeter Klausler return; 640a8a572cSPeter Klausler } 650a8a572cSPeter Klausler break; 660a8a572cSPeter Klausler } 670a8a572cSPeter Klausler // I/O error not caught! 680a8a572cSPeter Klausler if (msg) { 698ebf7411SSlava Zakharin #if !defined(RT_DEVICE_COMPILATION) 703b635714Speter klausler va_list ap; 713b635714Speter klausler va_start(ap, msg); 723b635714Speter klausler CrashArgs(msg, ap); 734f41994cSpeter klausler va_end(ap); 748ebf7411SSlava Zakharin #else 758ebf7411SSlava Zakharin Crash("not implemented yet: IOSTAT with varargs"); 768ebf7411SSlava Zakharin #endif 773b635714Speter klausler } else if (const char *errstr{IostatErrorString(iostatOrErrno)}) { 783b635714Speter klausler Crash(errstr); 79352d347aSAlexis Perry } else { 808ebf7411SSlava Zakharin #if !defined(RT_DEVICE_COMPILATION) 813b635714Speter klausler Crash("I/O error (errno=%d): %s", iostatOrErrno, 823b635714Speter klausler std::strerror(iostatOrErrno)); 838ebf7411SSlava Zakharin #else 848ebf7411SSlava Zakharin Crash("I/O error (errno=%d)", iostatOrErrno); 858ebf7411SSlava Zakharin #endif 86352d347aSAlexis Perry } 87352d347aSAlexis Perry } 88352d347aSAlexis Perry 893b635714Speter klausler void IoErrorHandler::SignalError(int iostatOrErrno) { 903b635714Speter klausler SignalError(iostatOrErrno, nullptr); 913b635714Speter klausler } 923b635714Speter klausler 9343fadefbSpeter klausler void IoErrorHandler::Forward( 9443fadefbSpeter klausler int ioStatOrErrno, const char *msg, std::size_t length) { 9579f6b812SPeter Klausler if (ioStatOrErrno != IostatOk) { 9679f6b812SPeter Klausler if (msg) { 97e9d0f8baSPeter Klausler SignalError(ioStatOrErrno, "%.*s", static_cast<int>(length), msg); 98e9d0f8baSPeter Klausler } else { 99e9d0f8baSPeter Klausler SignalError(ioStatOrErrno); 100e9d0f8baSPeter Klausler } 10143fadefbSpeter klausler } 10279f6b812SPeter Klausler } 10343fadefbSpeter klausler 1043b635714Speter klausler void IoErrorHandler::SignalEnd() { SignalError(IostatEnd); } 105352d347aSAlexis Perry 1063b635714Speter klausler void IoErrorHandler::SignalEor() { SignalError(IostatEor); } 1073b635714Speter klausler 1088db4dc86SPeter Klausler void IoErrorHandler::SignalPendingError() { 1098db4dc86SPeter Klausler int error{pendingError_}; 1108db4dc86SPeter Klausler pendingError_ = IostatOk; 1118db4dc86SPeter Klausler SignalError(error); 1128db4dc86SPeter Klausler } 1138db4dc86SPeter Klausler 1148ebf7411SSlava Zakharin void IoErrorHandler::SignalErrno() { SignalError(errno); } 1158ebf7411SSlava Zakharin 1163b635714Speter klausler bool IoErrorHandler::GetIoMsg(char *buffer, std::size_t bufferLength) { 1173b635714Speter klausler const char *msg{ioMsg_.get()}; 1183b635714Speter klausler if (!msg) { 1198db4dc86SPeter Klausler msg = IostatErrorString(ioStat_ == IostatOk ? pendingError_ : ioStat_); 120352d347aSAlexis Perry } 1213b635714Speter klausler if (msg) { 1223b635714Speter klausler ToFortranDefaultCharacter(buffer, bufferLength, msg); 1233b635714Speter klausler return true; 124352d347aSAlexis Perry } 125ea5efd1eSIsuru Fernando 126ea5efd1eSIsuru Fernando // Following code is taken from llvm/lib/Support/Errno.cpp 1278db4dc86SPeter Klausler // in LLVM v9.0.1 with inadequate modification for Fortran, 1288db4dc86SPeter Klausler // since rectified. 1298db4dc86SPeter Klausler bool ok{false}; 130f3c31d70SSlava Zakharin #if defined(RT_DEVICE_COMPILATION) 131f3c31d70SSlava Zakharin // strerror_r is not available on device. 132f3c31d70SSlava Zakharin msg = "errno description is not available on device"; 133f3c31d70SSlava Zakharin #elif HAVE_STRERROR_R 134ea5efd1eSIsuru Fernando // strerror_r is thread-safe. 135ea5efd1eSIsuru Fernando #if defined(__GLIBC__) && defined(_GNU_SOURCE) 136ea5efd1eSIsuru Fernando // glibc defines its own incompatible version of strerror_r 137ea5efd1eSIsuru Fernando // which may not use the buffer supplied. 1388db4dc86SPeter Klausler msg = ::strerror_r(ioStat_, buffer, bufferLength); 139ea5efd1eSIsuru Fernando #else 1408db4dc86SPeter Klausler ok = ::strerror_r(ioStat_, buffer, bufferLength) == 0; 141ea5efd1eSIsuru Fernando #endif 142ea5efd1eSIsuru Fernando #elif HAVE_DECL_STRERROR_S // "Windows Secure API" 1438db4dc86SPeter Klausler ok = ::strerror_s(buffer, bufferLength, ioStat_) == 0; 14443bec337SFangrui Song #else 145ea5efd1eSIsuru Fernando // Copy the thread un-safe result of strerror into 146ea5efd1eSIsuru Fernando // the buffer as fast as possible to minimize impact 147ea5efd1eSIsuru Fernando // of collision of strerror in multiple threads. 1488db4dc86SPeter Klausler msg = strerror(ioStat_); 149ea5efd1eSIsuru Fernando #endif 1508db4dc86SPeter Klausler if (msg) { 1518db4dc86SPeter Klausler ToFortranDefaultCharacter(buffer, bufferLength, msg); 152ea5efd1eSIsuru Fernando return true; 1538db4dc86SPeter Klausler } else if (ok) { 1548ebf7411SSlava Zakharin std::size_t copied{Fortran::runtime::strlen(buffer)}; 1558db4dc86SPeter Klausler if (copied < bufferLength) { 1568db4dc86SPeter Klausler std::memset(buffer + copied, ' ', bufferLength - copied); 1578db4dc86SPeter Klausler } 1588db4dc86SPeter Klausler return true; 1598db4dc86SPeter Klausler } else { 1608db4dc86SPeter Klausler return false; 1618db4dc86SPeter Klausler } 162352d347aSAlexis Perry } 163f3c31d70SSlava Zakharin 164f3c31d70SSlava Zakharin RT_OFFLOAD_API_GROUP_END 1651f879005STim Keith } // namespace Fortran::runtime::io 166