Skip to content

Commit a94d943

Browse files
committed
[flang] Fix actions at end of output record
It turns out that unformatted fixed-size output records do need to be padded out if short, in order to avoid a spurious EOF crash on a short record at the end of the file. While here in AdvanceRecord(), move the unformatted variable-length record header/footer writing code to here from EndIoStatement(). Differential revision: https://reviews.llvm.org/D88685
1 parent 78a9e62 commit a94d943

File tree

3 files changed

+25
-35
lines changed

3 files changed

+25
-35
lines changed

flang/runtime/io-stmt.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -698,32 +698,6 @@ bool UnformattedIoStatementState<DIR>::Emit(
698698
return ExternalIoStatementState<DIR>::Emit(data, bytes, elementBytes);
699699
}
700700

701-
template <Direction DIR>
702-
int UnformattedIoStatementState<DIR>::EndIoStatement() {
703-
ExternalFileUnit &unit{this->unit()};
704-
if constexpr (DIR == Direction::Output) {
705-
if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
706-
// Append the length of a sequential unformatted variable-length record
707-
// as its footer, then overwrite the reserved first four bytes of the
708-
// record with its length as its header. These four bytes were skipped
709-
// over in BeginUnformattedOutput().
710-
// TODO: Break very large records up into subrecords with negative
711-
// headers &/or footers
712-
union {
713-
std::uint32_t u;
714-
char c[sizeof u];
715-
} u;
716-
u.u = unit.furthestPositionInRecord - sizeof u;
717-
// TODO: Convert record length to little-endian on big-endian host?
718-
if (!(this->Emit(u.c, sizeof u) &&
719-
(this->HandleAbsolutePosition(0), this->Emit(u.c, sizeof u)))) {
720-
return false;
721-
}
722-
}
723-
}
724-
return ExternalIoStatementState<DIR>::EndIoStatement();
725-
}
726-
727701
template class InternalIoStatementState<Direction::Output>;
728702
template class InternalIoStatementState<Direction::Input>;
729703
template class InternalFormattedIoStatementState<Direction::Output>;

flang/runtime/io-stmt.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ class UnformattedIoStatementState : public ExternalIoStatementState<DIR> {
322322
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
323323
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
324324
bool Emit(const char *, std::size_t, std::size_t elementBytes = 0);
325-
int EndIoStatement();
326325
};
327326

328327
class OpenStatementState : public ExternalIoStatementBase {

flang/runtime/unit.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,15 +406,32 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
406406
FinishReadingRecord(handler);
407407
BeginReadingRecord(handler);
408408
} else { // Direction::Output
409-
if (!isUnformatted) {
410-
if (isFixedRecordLength && recordLength) {
411-
if (furthestPositionInRecord < *recordLength) {
412-
WriteFrame(frameOffsetInFile_, *recordLength, handler);
413-
std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord,
414-
' ', *recordLength - furthestPositionInRecord);
415-
}
409+
if (isFixedRecordLength && recordLength) {
410+
// Pad remainder of fixed length record
411+
if (furthestPositionInRecord < *recordLength) {
412+
WriteFrame(
413+
frameOffsetInFile_, recordOffsetInFrame_ + *recordLength, handler);
414+
std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord,
415+
isUnformatted ? 0 : ' ', *recordLength - furthestPositionInRecord);
416+
}
417+
} else {
418+
positionInRecord = furthestPositionInRecord;
419+
if (isUnformatted) {
420+
// Append the length of a sequential unformatted variable-length record
421+
// as its footer, then overwrite the reserved first four bytes of the
422+
// record with its length as its header. These four bytes were skipped
423+
// over in BeginUnformattedIO<Output>().
424+
// TODO: Break very large records up into subrecords with negative
425+
// headers &/or footers
426+
std::uint32_t length;
427+
length = furthestPositionInRecord - sizeof length;
428+
ok &= Emit(reinterpret_cast<const char *>(&length), sizeof length,
429+
sizeof length, handler);
430+
positionInRecord = 0;
431+
ok &= Emit(reinterpret_cast<const char *>(&length), sizeof length,
432+
sizeof length, handler);
416433
} else {
417-
positionInRecord = furthestPositionInRecord;
434+
// Terminate formatted variable length record
418435
ok &= Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
419436
}
420437
}

0 commit comments

Comments
 (0)