libc: квирки DSS — возврат WRITE и лимит манипуляторов; тесты fdmax/fbench

- ESTEX WRITE ($14) на успехе возвращает DE=0, а НЕ счётчик записанного
  (вопреки докам; solid-c в своём fflush тоже отключил сравнение по
  счётчику) — write() теперь судит по CF/A: CF=0&A=0 → n,
  CF=0&A!=0 → ENOSPC/-1
- DSS выдаёт 8 манипуляторов (fd 2..9; fd 1 держит шелл под запущенный
  exe), а 9-й OPEN не возвращает 06h — ВЕШАЕТ систему; предохранитель
  _fd_guard: счётчик в open()/close(), отказ EMFILE без захода в DSS
- tests/fdmax — эмпирика лимита (8 хендлов, затем EMFILE=6);
  tests/fbench — бенчмарк буферизации (floor 512-байтными read,
  оценка небуферизованного по 1-байтным, fgetc/fgets/fputc)
- filetest расширен: raw-probe возврата write, сценарий r+
  (чтение-запись-чтение с инвалидацией буфера), ungetc, fprintf

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 16:09:29 +03:00
parent 48d552bf3a
commit 057dd615ba
11 changed files with 361 additions and 58 deletions
+8
View File
@@ -0,0 +1,8 @@
# Build fdmax.exe — проверка лимита открытых файлов DSS/FILE-таблицы.
# TEST.TXT нужен тесту как открываемый файл — кладём на дискету
# и при одиночном `make run` (берём из tests/cat).
PROJ_ROOT := $(abspath $(CURDIR)/../..)
EXAMPLE := fdmax
EXTRA_DATA := ../cat/test.txt
include $(PROJ_ROOT)/app.mk
+57
View File
@@ -0,0 +1,57 @@
/*
* fdmax — эмпирическая проверка лимита одновременно открытых файлов.
*
* ФАКТ (прогон 2026-07-06, DSS 1.71.57): DSS выдал 8 манипуляторов
* (fd 2..9; fd 1 держит шелл DSS под запущенный .exe), а 9-й OPEN
* НЕ вернул ошибку — ПОВЕСИЛ систему. После этого в libc/io/open.c
* добавлен предохранитель _fd_guard (отказ EMFILE на 9-м open без
* захода в DSS), и этот тест снова безопасен.
*
* 1) Низкий уровень: open("TEST.TXT") в цикле — ожидание: 8 хендлов,
* затем EMFILE=6 от предохранителя libc (не от DSS!).
* 2) Высокий уровень: fopen до NULL — таблица OPEN_MAX (8), EMFILE.
*
* Требует TEST.TXT на диске (без него обе фазы дадут ENOENT=3).
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define TRY_MAX 32
int main(void)
{
int fds[TRY_MAX];
int n = 0;
/* ----- 1. Голые манипуляторы DSS ----- */
errno = 0;
while (n < TRY_MAX) {
int fd = open("TEST.TXT", O_RDONLY);
if (fd < 0) break;
fds[n++] = fd;
printf("open #%d -> fd=%d\n", n, fd);
}
printf("low-level: %d handles, then errno=%d (%s)\n",
n, errno, strerror(errno));
for (int i = 0; i < n; i++) close(fds[i]);
/* ----- 2. fopen / таблица FILE ----- */
FILE *fps[TRY_MAX];
int m = 0;
errno = 0;
while (m < TRY_MAX) {
FILE *fp = fopen("TEST.TXT", "r");
if (!fp) break;
fps[m++] = fp;
}
printf("fopen: %d streams (OPEN_MAX=%d), then errno=%d (%s)\n",
m, OPEN_MAX, errno, strerror(errno));
for (int i = 0; i < m; i++) fclose(fps[i]);
puts("fdmax done.");
return 0;
}