Skip to content

[flang][runtime] Detect byte order reversal problems #129093

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions flang-rt/lib/runtime/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ void ExternalFileUnit::EndIoStatement() {
void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
IoErrorHandler &handler) {
RUNTIME_CHECK(handler, access == Access::Sequential);
std::int32_t header{0}, footer{0};
std::uint32_t header{0}, footer{0};
std::size_t need{recordOffsetInFrame_ + sizeof header};
std::size_t got{ReadFrame(frameOffsetInFile_, need, handler)};
// Try to emit informative errors to help debug corrupted files.
Expand All @@ -528,17 +528,41 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
recordLength = sizeof header + header; // does not include footer
need = recordOffsetInFrame_ + *recordLength + sizeof footer;
got = ReadFrame(frameOffsetInFile_, need, handler);
if (got < need) {
if (got >= need) {
footer = ReadHeaderOrFooter(recordOffsetInFrame_ + *recordLength);
}
if (frameOffsetInFile_ == 0 && recordOffsetInFrame_ == 0 &&
(got < need || footer != header)) {
// Maybe an omitted or incorrect byte swap flag setting?
// Try it the other way, since this is the first record.
// (N.B. Won't work on files starting with empty records, but there's
// no good way to know later if all preceding records were empty.)
swapEndianness_ = !swapEndianness_;
std::uint32_t header2{ReadHeaderOrFooter(0)};
std::size_t recordLength2{sizeof header2 + header2};
std::size_t need2{recordLength2 + sizeof footer};
std::size_t got2{ReadFrame(0, need2, handler)};
if (got2 >= need2) {
std::uint32_t footer2{ReadHeaderOrFooter(recordLength2)};
if (footer2 == header2) {
error = "Unformatted variable-length sequential file input "
"failed on the first record, probably due to a need "
"for byte order data conversion; consider adding "
"CONVERT='SWAP' to the OPEN statement or adding "
"FORT_CONVERT=SWAP to the execution environment";
}
}
swapEndianness_ = !swapEndianness_;
}
if (error) {
} else if (got < need) {
error = "Unformatted variable-length sequential file input failed at "
"record #%jd (file offset %jd): hit EOF reading record with "
"length %jd bytes";
} else {
footer = ReadHeaderOrFooter(recordOffsetInFrame_ + *recordLength);
if (footer != header) {
error = "Unformatted variable-length sequential file input failed at "
"record #%jd (file offset %jd): record header has length %jd "
"that does not match record footer (%jd)";
}
} else if (footer != header) {
error = "Unformatted variable-length sequential file input failed at "
"record #%jd (file offset %jd): record header has length %jd "
"that does not match record footer (%jd)";
}
}
if (error) {
Expand Down Expand Up @@ -590,7 +614,7 @@ void ExternalFileUnit::BackspaceFixedRecord(IoErrorHandler &handler) {

void ExternalFileUnit::BackspaceVariableUnformattedRecord(
IoErrorHandler &handler) {
std::int32_t header{0};
std::uint32_t header{0};
auto headerBytes{static_cast<std::int64_t>(sizeof header)};
frameOffsetInFile_ += recordOffsetInFrame_;
recordOffsetInFrame_ = 0;
Expand Down Expand Up @@ -775,8 +799,8 @@ void ExternalFileUnit::PopChildIo(ChildIo &child) {
child_.reset(child.AcquirePrevious().release()); // deletes top child
}

std::int32_t ExternalFileUnit::ReadHeaderOrFooter(std::int64_t frameOffset) {
std::int32_t word;
std::uint32_t ExternalFileUnit::ReadHeaderOrFooter(std::int64_t frameOffset) {
std::uint32_t word;
char *wordPtr{reinterpret_cast<char *>(&word)};
std::memcpy(wordPtr, Frame() + frameOffset, sizeof word);
if (swapEndianness_) {
Expand Down
2 changes: 1 addition & 1 deletion flang-rt/lib/runtime/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class ExternalFileUnit : public ConnectionState,
RT_API_ATTRS void CommitWrites();
RT_API_ATTRS bool CheckDirectAccess(IoErrorHandler &);
RT_API_ATTRS void HitEndOnRead(IoErrorHandler &);
RT_API_ATTRS std::int32_t ReadHeaderOrFooter(std::int64_t frameOffset);
RT_API_ATTRS std::uint32_t ReadHeaderOrFooter(std::int64_t frameOffset);

Lock lock_;

Expand Down