[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
This commit is contained in:
parent
78a9e62aa6
commit
a94d943f1a
|
@ -698,32 +698,6 @@ bool UnformattedIoStatementState<DIR>::Emit(
|
|||
return ExternalIoStatementState<DIR>::Emit(data, bytes, elementBytes);
|
||||
}
|
||||
|
||||
template <Direction DIR>
|
||||
int UnformattedIoStatementState<DIR>::EndIoStatement() {
|
||||
ExternalFileUnit &unit{this->unit()};
|
||||
if constexpr (DIR == Direction::Output) {
|
||||
if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
|
||||
// Append the length of a sequential unformatted variable-length record
|
||||
// as its footer, then overwrite the reserved first four bytes of the
|
||||
// record with its length as its header. These four bytes were skipped
|
||||
// over in BeginUnformattedOutput().
|
||||
// TODO: Break very large records up into subrecords with negative
|
||||
// headers &/or footers
|
||||
union {
|
||||
std::uint32_t u;
|
||||
char c[sizeof u];
|
||||
} u;
|
||||
u.u = unit.furthestPositionInRecord - sizeof u;
|
||||
// TODO: Convert record length to little-endian on big-endian host?
|
||||
if (!(this->Emit(u.c, sizeof u) &&
|
||||
(this->HandleAbsolutePosition(0), this->Emit(u.c, sizeof u)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ExternalIoStatementState<DIR>::EndIoStatement();
|
||||
}
|
||||
|
||||
template class InternalIoStatementState<Direction::Output>;
|
||||
template class InternalIoStatementState<Direction::Input>;
|
||||
template class InternalFormattedIoStatementState<Direction::Output>;
|
||||
|
|
|
@ -322,7 +322,6 @@ public:
|
|||
using ExternalIoStatementState<DIR>::ExternalIoStatementState;
|
||||
bool Receive(char *, std::size_t, std::size_t elementBytes = 0);
|
||||
bool Emit(const char *, std::size_t, std::size_t elementBytes = 0);
|
||||
int EndIoStatement();
|
||||
};
|
||||
|
||||
class OpenStatementState : public ExternalIoStatementBase {
|
||||
|
|
|
@ -406,15 +406,32 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
|
|||
FinishReadingRecord(handler);
|
||||
BeginReadingRecord(handler);
|
||||
} else { // Direction::Output
|
||||
if (!isUnformatted) {
|
||||
if (isFixedRecordLength && recordLength) {
|
||||
if (furthestPositionInRecord < *recordLength) {
|
||||
WriteFrame(frameOffsetInFile_, *recordLength, handler);
|
||||
std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord,
|
||||
' ', *recordLength - furthestPositionInRecord);
|
||||
}
|
||||
if (isFixedRecordLength && recordLength) {
|
||||
// Pad remainder of fixed length record
|
||||
if (furthestPositionInRecord < *recordLength) {
|
||||
WriteFrame(
|
||||
frameOffsetInFile_, recordOffsetInFrame_ + *recordLength, handler);
|
||||
std::memset(Frame() + recordOffsetInFrame_ + furthestPositionInRecord,
|
||||
isUnformatted ? 0 : ' ', *recordLength - furthestPositionInRecord);
|
||||
}
|
||||
} else {
|
||||
positionInRecord = furthestPositionInRecord;
|
||||
if (isUnformatted) {
|
||||
// Append the length of a sequential unformatted variable-length record
|
||||
// as its footer, then overwrite the reserved first four bytes of the
|
||||
// record with its length as its header. These four bytes were skipped
|
||||
// over in BeginUnformattedIO<Output>().
|
||||
// TODO: Break very large records up into subrecords with negative
|
||||
// headers &/or footers
|
||||
std::uint32_t length;
|
||||
length = furthestPositionInRecord - sizeof length;
|
||||
ok &= Emit(reinterpret_cast<const char *>(&length), sizeof length,
|
||||
sizeof length, handler);
|
||||
positionInRecord = 0;
|
||||
ok &= Emit(reinterpret_cast<const char *>(&length), sizeof length,
|
||||
sizeof length, handler);
|
||||
} else {
|
||||
positionInRecord = furthestPositionInRecord;
|
||||
// Terminate formatted variable length record
|
||||
ok &= Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue