You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

未重置getline的size参数导致GNU regex匹配失败的原因

问题:getline()的size参数为何影响GNU regex的匹配结果?

现有一段C代码,包含read_files()函数(用于读取多个文本文件)和match()函数(借助GNU regex库实现字符串模式匹配)。其中read_files()调用getline()时将初始size参数设为0,让其从默认120字节的缓冲区开始按需扩容。

运行代码后发现:本应匹配正则^[a-zA-Z0-9]+$的字符串"jack"匹配失败;但如果在读取第一个文件后将len重置为0,regex匹配就会恢复正常。


代码实现

#include <limits.h> // for PATH_MAX
#include <regex.h>  // for regcomp, regerror, regexec, regfree, size_t, REG...
#include <stdio.h>  // for printf, fprintf, NULL, fclose, fopen, getline
#include <stdlib.h> // for exit, free, EXIT_FAILURE

int match(const char *regex_str, const char *str) {

    regex_t regex;
    int reti;
    char msgbuf[100];

    /* Compile regular expression */
    reti = regcomp(&regex, regex_str, REG_EXTENDED);
    if (reti) {
        fprintf(stderr, "Could not compile regex\n");
        exit(1);
    }

    /* Execute regular expression */
    reti = regexec(&regex, str, 0, NULL, 0);
    if (!reti) {
        return 1;
    } else if (reti == REG_NOMATCH) {
        return 0;
    } else {
        regerror(reti, &regex, msgbuf, sizeof(msgbuf));
        fprintf(stderr, "Regex match failed: %s\n", msgbuf);
        exit(1);
    }

    /* Free memory allocated to the pattern buffer by regcomp() */
    regfree(&regex);
}

void read_files() {

    size_t path_count = 2;
    char pathnames[2][PATH_MAX] = {"./tmp/test0.conf", "./tmp/test1.conf"};

    FILE *fp;
    char *line = NULL;
    size_t len = 0;
    ssize_t read_count;

    for (int i = 0; i < path_count; i++) {
        printf("opening file %s\n", pathnames[i]);

        fp = fopen(pathnames[i], "r");
        if (fp == NULL) {
            printf("internal error,couldn't open file %s\"}", pathnames[i]);
            exit(EXIT_FAILURE);
        }
        int linenum=1;
        while ((read_count = getline(&line, &len, fp)) != -1) {
            printf("%d: %s",linenum,line);
            linenum++;
        }
        printf("len: %zu\n", len);

        fclose(fp);
        // len=0; // this is the line that fixes the bug, if i reset len to 0 after reading the first file then everything works as expected, if i don't reset it then regex matching fails
        if (line)
            free(line);
    }
}

int main(int argc, char *argv[]) {
    read_files();

    if (!match("^[a-zA-Z0-9]+$", "jack")) {
        printf("input don't match\n");
    }
}

测试文件内容

test0.conf

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

test1.conf

testing123

运行输出

opening file ./tmp/test0.conf
1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
len: 240
opening file ./tmp/test1.conf
1: testing123
len: 240
input don't match

原因分析

问题的核心并非getline()的len参数直接影响regex,而是内存操作的未定义行为导致后续regex库出错:

  1. 在read_files()的循环中,处理完第一个文件后,执行了free(line)但没有将line重置为NULL,同时len保留了240的数值。
  2. 进入第二个文件的处理时,调用getline(&line, &len, fp),此时line是指向已释放内存的野指针,而getline会假设*line是一块由malloc分配、大小为*len的有效缓冲区,尝试复用这块内存。
  3. 对已释放内存的读写属于未定义行为,会导致堆内存损坏——这种损坏可能影响后续match()函数中regex库的内存操作(比如regcomp分配的正则表达式缓冲区被破坏),最终导致原本应该匹配的字符串匹配失败。

当在free(line)后将len重置为0,或者同时将line置为NULL,getline会重新分配新的有效缓冲区,避免了野指针和内存损坏问题,regex匹配也就恢复正常了。


内容的提问来源于stack exchange,提问作者MOHAMMAD RASIM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 23:18:25