c - 是否有任何 gcc 编译器选项或类似的东西来绕过过时的gets 函数?

标签 c string security gcc gets

让我们先解决这个问题:我完全明白为什么 gets函数已被弃用以及如何在不受控制的环境中恶意使用它。我确信该功能可以在我的设置中安全使用。
“替代”功能不适用于我的用例。我正在编写的软件对性能非常敏感,所以使用 fgets然后使用一个完整的字符串循环(明确地或通过像 strlen 这样的辅助函数)来摆脱字符串末尾的换行符根本行不通。写我自己的 gets函数使用 getchar或类似的东西也可能比 native 实现效率低得多(更不用说非常容易出错)。
Visual Studio 编译器有一个 gets_s符合我需要的函数,但是在 gcc 中找不到这个函数。是否有任何编译器选项/标志可以恢复此功能和/或它实现的某些替代功能?
先感谢您。

最佳答案

实现自己的保险箱 gets()函数使用 getchar_unlocked()很容易而且相当有效。
如果您的应用程序对性能如此敏感,您会认为 fgets()并且删除扫描将成为瓶颈,您可能根本不应该使用流函数并使用较低级别的 read()系统调用或内存映射文件。
在任何情况下,您都应该仔细地对您的应用程序进行基准测试,并使用分析工具来确定时间花在哪里。
这是一个简单的实现,它返回行长度但将行截断为适合目标数组 buf 的任何值长度n并返回 EOF在文件末尾:

int my_gets(char *buf, size_t n) {
    int c;
    size_t i = 0;
    while ((c = getchar_unlocked()) != EOF && c != '\n') {
        if (i < n) {
            buf[i] = c;
        }
        i++;
    }
    if (i < n) {
        buf[i] = '\0';
    } else
    if (n > 0) {
        buf[n - 1] = '\0';
    }
    if (c == EOF && i == 0) {
        return EOF;
    } else {
        return (int)i;
    }
}
如果您的目标是逐行解析日志文件,并且只有此函数从 stdin 中读取,您可以使用 read 实现自定义缓冲方案或 freadgets() 的自定义版本中.这将是便携且快速的,但不是线程安全的,也不是优雅的。
这是一个比 fgets() 快 20% 的示例在我的系统上:
/* read a line from stdin
   strip extra characters and the newline
   return the number of characters before the newline, possibly >= n
   return EOF at end of file
 */
static char gets_buffer[65536];
static size_t gets_pos, gets_end;

int my_fast_gets(char *buf, size_t n) {
    size_t pos = 0;
    for (;;) {
        char *p = gets_buffer + gets_pos;
        size_t len = gets_end - gets_pos;
        char *q = memchr(p, '\n', len);
        if (q != NULL) {
            len = q - p;
        }
        if (pos + len < n) {
            memcpy(buf + pos, p, len);
            buf[pos + len] = '\0';
        } else
        if (pos < n) {
            memcpy(buf + pos, p, n - pos - 1);
            buf[n - 1] = '\0';
        }
        pos += len;
        gets_pos += len;
        if (q != NULL) {
            gets_pos += 1;
            return (int)pos;
        }
        gets_pos = 0;
        gets_end = fread(gets_buffer, 1, sizeof gets_buffer, stdin);
        if (gets_end == 0) {
            return pos == 0 ? EOF : (int)pos;
        }
    }
}

关于c - 是否有任何 gcc 编译器选项或类似的东西来绕过过时的gets 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67664505/

相关文章:

java - Java 中面向互联网的 Web 服务器的安全选择是什么?

c - 使用(显然)空的 C 函数

c - `memcpy((void *)dest, src, n)` 和 `volatile` 数组安全吗?

C 套接字 : recv() blocks when all data is downloaded

c++ - CComBSTR内存分配

c# - 如何保护将重要数据发布到我的数据库的公共(public) ASMX 页面

c - 错误 : array type 'va_list' (aka '__builtin_va_list' ) is not assignable

java - 为什么我们在 for 循环中执行 { i < s.length() - k } 请解释逻辑。给定字符串 s 和 int k

c# - 检查一个单词是否包含不在字母表数组中的字符

java - 我必须把@DeclareRoles 放在哪里?