Merge pull request #3612 from karim200003/fix/libc-fgets-nonpositive-size
fix(libc): fail fgets with a size of 0 or less like FreeBSD
This commit is contained in:
commit
bb67fe1a34
|
|
@ -42,7 +42,7 @@ class FileStream {
|
|||
std::byte _reserved[256 - sizeof(GuestFilePrefix)]{};
|
||||
std::FILE* _handle;
|
||||
bool _dynamic;
|
||||
bool encodingError = false;
|
||||
bool guestError = false;
|
||||
|
||||
public:
|
||||
explicit FileStream(std::FILE* handle, bool dynamic = false) : _handle(handle), _dynamic(dynamic) {
|
||||
|
|
@ -72,7 +72,7 @@ public:
|
|||
bool Reopen(const std::filesystem::path& filename, const char* mode) {
|
||||
auto* previous = GetHandle();
|
||||
_guest = {};
|
||||
encodingError = false;
|
||||
guestError = false;
|
||||
#ifdef _WIN32
|
||||
std::wstring wideMode;
|
||||
for (const char character : std::string_view(mode)) wideMode.push_back(static_cast<unsigned char>(character));
|
||||
|
|
@ -94,7 +94,7 @@ public:
|
|||
_guest.readRemaining = 0;
|
||||
_guest.writeRemaining = 0;
|
||||
_guest.flags = static_cast<std::int16_t>((_guest.flags & ~0x60) |
|
||||
(std::feof(GetHandle()) ? 0x20 : 0) | (std::ferror(GetHandle()) || encodingError ? 0x40 : 0));
|
||||
(std::feof(GetHandle()) ? 0x20 : 0) | (std::ferror(GetHandle()) || guestError ? 0x40 : 0));
|
||||
}
|
||||
|
||||
void SyncUnlockedStatus() {
|
||||
|
|
@ -108,17 +108,17 @@ public:
|
|||
const bool error = ::ferror_unlocked(GetHandle()) != 0;
|
||||
#endif
|
||||
_guest.flags = static_cast<std::int16_t>((_guest.flags & ~0x60) |
|
||||
(endOfFile ? 0x20 : 0) | (error || encodingError ? 0x40 : 0));
|
||||
(endOfFile ? 0x20 : 0) | (error || guestError ? 0x40 : 0));
|
||||
}
|
||||
|
||||
void SetEncodingError() {
|
||||
encodingError = true;
|
||||
void SetError() {
|
||||
guestError = true;
|
||||
SyncStatus();
|
||||
}
|
||||
|
||||
void ClearError() {
|
||||
std::clearerr(GetHandle());
|
||||
encodingError = false;
|
||||
guestError = false;
|
||||
SyncStatus();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ std::int32_t APS5_VABI ungetwc_nid_postfix(std::int32_t value, FileStream* strea
|
|||
if (value == -1) return -1;
|
||||
if (value < 0 || value > 255) {
|
||||
errno = 86;
|
||||
stream->SetEncodingError();
|
||||
stream->SetError();
|
||||
return -1;
|
||||
}
|
||||
const int result = std::ungetc(value, GetNativeStream(stream));
|
||||
|
|
@ -69,6 +69,11 @@ int APS5_VABI ungetc_nid_postfix(int value, FileStream* stream) {
|
|||
return result;
|
||||
}
|
||||
char* APS5_VABI fgets_nid_postfix(char* buffer, int size, FileStream* stream) {
|
||||
if (size <= 0) {
|
||||
stream->SetError();
|
||||
errno = 22;
|
||||
return nullptr;
|
||||
}
|
||||
auto* result = std::fgets(buffer, size, GetNativeStream(stream));
|
||||
stream->SyncStatus();
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
|
@ -121,7 +122,7 @@ static void CheckUnlockedStreams() {
|
|||
Require(std::ungetc('Q', stream.GetHandle()) == 'Q');
|
||||
Require(getc_unlocked_nid_postfix(&stream) == 'Q' && !(guest.flags & 0x20));
|
||||
std::rewind(stream.GetHandle());
|
||||
stream.SetEncodingError();
|
||||
stream.SetError();
|
||||
Require(putc_unlocked_nid_postfix('R', &stream) == 'R' && (guest.flags & 0x40));
|
||||
clearerr_nid_postfix(&stream);
|
||||
Require(!(guest.flags & 0x40));
|
||||
|
|
@ -229,6 +230,27 @@ static void CheckUnlockedStreamLock(bool write) {
|
|||
stream.Close();
|
||||
}
|
||||
|
||||
static void CheckFgetsSize() {
|
||||
FileStream stream(std::tmpfile());
|
||||
Require(fwrite_nid_postfix("line\n", 1, 5, &stream) == 5);
|
||||
rewind_nid_postfix(&stream);
|
||||
for (const int size : {0, -1, std::numeric_limits<int>::min()}) {
|
||||
char buffer[8];
|
||||
std::memset(buffer, '!', sizeof(buffer));
|
||||
*__error_nid_postfix() = 0;
|
||||
Require(fgets_nid_postfix(buffer, size, &stream) == nullptr);
|
||||
Require(*__error_nid_postfix() == 22 && ferror_nid_postfix(&stream) != 0 && feof_nid_postfix(&stream) == 0);
|
||||
Require(buffer[0] == '!' && ftello_nid_postfix(&stream) == 0);
|
||||
Require(ferror_nid_postfix(&stream) != 0);
|
||||
clearerr_nid_postfix(&stream);
|
||||
Require(ferror_nid_postfix(&stream) == 0);
|
||||
}
|
||||
char line[8]{};
|
||||
Require(fgets_nid_postfix(line, sizeof(line), &stream) == line && std::strcmp(line, "line\n") == 0);
|
||||
Require(ferror_nid_postfix(&stream) == 0);
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
static void CheckRewind() {
|
||||
FileStream stream(std::tmpfile());
|
||||
Require(fwrite_nid_postfix("ab", 1, 2, &stream) == 2);
|
||||
|
|
@ -239,7 +261,7 @@ static void CheckRewind() {
|
|||
rewind_nid_postfix(&stream);
|
||||
Require(fgetc_nid_postfix(&stream) == 'a' && fgetc_nid_postfix(&stream) == 'b' && fgetc_nid_postfix(&stream) == EOF);
|
||||
Require(feof_nid_postfix(&stream) != 0);
|
||||
stream.SetEncodingError();
|
||||
stream.SetError();
|
||||
Require(ferror_nid_postfix(&stream) != 0);
|
||||
rewind_nid_postfix(&stream);
|
||||
Require(feof_nid_postfix(&stream) == 0 && ferror_nid_postfix(&stream) == 0 && fgetc_nid_postfix(&stream) == 'a');
|
||||
|
|
@ -511,6 +533,7 @@ int main() {
|
|||
Require(fgetc_nid_postfix(&locked) == 'A' && fgetc_nid_postfix(&locked) == 'B');
|
||||
locked.Close();
|
||||
CheckRewind();
|
||||
CheckFgetsSize();
|
||||
CheckUnlockedStreams();
|
||||
CheckUnlockedStreamLock(false);
|
||||
CheckUnlockedStreamLock(true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue