Skip to content

Commit abe1ecf

Browse files
authored
[flang][runtime] Detect byte order reversal problems (#129093)
When reading an unformatted sequential file with variable-length records, detect byte order reversal problems with the first record's header and footer words, and emit a more detailed error message.
1 parent 5401c67 commit abe1ecf

File tree

2 files changed

+37
-13
lines changed

2 files changed

+37
-13
lines changed

flang-rt/lib/runtime/unit.cpp

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ void ExternalFileUnit::EndIoStatement() {
511511
void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
512512
IoErrorHandler &handler) {
513513
RUNTIME_CHECK(handler, access == Access::Sequential);
514-
std::int32_t header{0}, footer{0};
514+
std::uint32_t header{0}, footer{0};
515515
std::size_t need{recordOffsetInFrame_ + sizeof header};
516516
std::size_t got{ReadFrame(frameOffsetInFile_, need, handler)};
517517
// Try to emit informative errors to help debug corrupted files.
@@ -528,17 +528,41 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
528528
recordLength = sizeof header + header; // does not include footer
529529
need = recordOffsetInFrame_ + *recordLength + sizeof footer;
530530
got = ReadFrame(frameOffsetInFile_, need, handler);
531-
if (got < need) {
531+
if (got >= need) {
532+
footer = ReadHeaderOrFooter(recordOffsetInFrame_ + *recordLength);
533+
}
534+
if (frameOffsetInFile_ == 0 && recordOffsetInFrame_ == 0 &&
535+
(got < need || footer != header)) {
536+
// Maybe an omitted or incorrect byte swap flag setting?
537+
// Try it the other way, since this is the first record.
538+
// (N.B. Won't work on files starting with empty records, but there's
539+
// no good way to know later if all preceding records were empty.)
540+
swapEndianness_ = !swapEndianness_;
541+
std::uint32_t header2{ReadHeaderOrFooter(0)};
542+
std::size_t recordLength2{sizeof header2 + header2};
543+
std::size_t need2{recordLength2 + sizeof footer};
544+
std::size_t got2{ReadFrame(0, need2, handler)};
545+
if (got2 >= need2) {
546+
std::uint32_t footer2{ReadHeaderOrFooter(recordLength2)};
547+
if (footer2 == header2) {
548+
error = "Unformatted variable-length sequential file input "
549+
"failed on the first record, probably due to a need "
550+
"for byte order data conversion; consider adding "
551+
"CONVERT='SWAP' to the OPEN statement or adding "
552+
"FORT_CONVERT=SWAP to the execution environment";
553+
}
554+
}
555+
swapEndianness_ = !swapEndianness_;
556+
}
557+
if (error) {
558+
} else if (got < need) {
532559
error = "Unformatted variable-length sequential file input failed at "
533560
"record #%jd (file offset %jd): hit EOF reading record with "
534561
"length %jd bytes";
535-
} else {
536-
footer = ReadHeaderOrFooter(recordOffsetInFrame_ + *recordLength);
537-
if (footer != header) {
538-
error = "Unformatted variable-length sequential file input failed at "
539-
"record #%jd (file offset %jd): record header has length %jd "
540-
"that does not match record footer (%jd)";
541-
}
562+
} else if (footer != header) {
563+
error = "Unformatted variable-length sequential file input failed at "
564+
"record #%jd (file offset %jd): record header has length %jd "
565+
"that does not match record footer (%jd)";
542566
}
543567
}
544568
if (error) {
@@ -590,7 +614,7 @@ void ExternalFileUnit::BackspaceFixedRecord(IoErrorHandler &handler) {
590614

591615
void ExternalFileUnit::BackspaceVariableUnformattedRecord(
592616
IoErrorHandler &handler) {
593-
std::int32_t header{0};
617+
std::uint32_t header{0};
594618
auto headerBytes{static_cast<std::int64_t>(sizeof header)};
595619
frameOffsetInFile_ += recordOffsetInFrame_;
596620
recordOffsetInFrame_ = 0;
@@ -775,8 +799,8 @@ void ExternalFileUnit::PopChildIo(ChildIo &child) {
775799
child_.reset(child.AcquirePrevious().release()); // deletes top child
776800
}
777801

778-
std::int32_t ExternalFileUnit::ReadHeaderOrFooter(std::int64_t frameOffset) {
779-
std::int32_t word;
802+
std::uint32_t ExternalFileUnit::ReadHeaderOrFooter(std::int64_t frameOffset) {
803+
std::uint32_t word;
780804
char *wordPtr{reinterpret_cast<char *>(&word)};
781805
std::memcpy(wordPtr, Frame() + frameOffset, sizeof word);
782806
if (swapEndianness_) {

flang-rt/lib/runtime/unit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class ExternalFileUnit : public ConnectionState,
210210
RT_API_ATTRS void CommitWrites();
211211
RT_API_ATTRS bool CheckDirectAccess(IoErrorHandler &);
212212
RT_API_ATTRS void HitEndOnRead(IoErrorHandler &);
213-
RT_API_ATTRS std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset);
213+
RT_API_ATTRS std::uint32_t ReadHeaderOrFooter(std::int64_t frameOffset);
214214

215215
Lock lock_;
216216

0 commit comments

Comments
 (0)