On Wednesday 31 July 2024 00:13:24 LIU Hao wrote: > 在 2024-07-29 02:58, Pali Rohár 写道: > > ssp/gets_chk.c: In function ‘__gets_chk’: > > ssp/gets_chk.c:20:12: warning: call to ‘gets’ declared with attribute > > warning: Using gets() is always unsafe - use fgets() instead > > return gets(dst); > > These can be replaced with `abort()`.
This __gets_chk() function is calling gets() just because it is dynamically allocating temporary buffer to which it reads stdin and then after validation, it transfer content of the temporary buffer into the final output buffer. What about reading stdin directly into the final output buffer? And completely get rid of those repeated gets() calls and dynamic allocation of temporary buffer? Now I have played with this and I think it could be possible via scanf() with safe format with upper bound checks: "%<size>[^\n]%n%c" Martin, I see that you wrote this __gets_chk() function. What do you think about it? Here is my attempt: #include <stdio.h> #include <inttypes.h> #ifdef _WIN64 #define SIZET_DIGITS 20 #else #define SIZET_DIGITS 10 #endif void __cdecl __chk_fail(void) __attribute__((__noreturn__)); char *__cdecl __gets_chk(char *dst, size_t bufsize); char *__cdecl __gets_chk(char *dst, size_t bufsize) { char format[10 + SIZET_DIGITS]; char newline[2]; /* "%1[\n]" writes null-term, but %c does not */ int count; int ret; if (bufsize <= 1) { ret = getchar(); if (ret == EOF) return NULL; if (bufsize == 0 || ret != '\n') __chk_fail(); dst[0] = '\0'; return dst; } /* bufsize-1 must be positive as it is maximum width for %[ format */ if (__ms_sprintf(format, "%%%" SCNuPTR "[^\n]%%n%%c", bufsize-1) < 0) return NULL; /* * scanf() returns zero if the "%[...]" format does not match any * character and there is some character waiting in stdin queue. * So if the first character in input queue does not match "%[^\n]" * then it should match "%[\n]". If it does not match "\n" then * between consecutive scanf() calls some other thread must have * read something from the input queue and newline is not the first * character anymore. Try again with non-newline. Loop until we read * something (return value is positive) or error occurs (return value * is negative). This method should be race free and should not cause * reading of invalid data. */ do { ret = __ms_scanf(format, dst, &count, newline); if (ret == 0) { ret = __ms_scanf("%1[\n]", newline); if (ret == 1) { dst[0] = '\0'; count = 0; ret = 3; } } } while (ret == 0); if (ret < 2) return NULL; if (ret == 3 && (size_t)count == bufsize-1 && *newline != '\n') __chk_fail(); return dst; } _______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public