c - C 中的 realloc 字符串表在第四次迭代时崩溃

标签 c realloc string-table

虽然这里有几个关于这个问题的答案:我仍然无法将它们适合以下代码,因为它在 processFile 的第四次迭代上出现segfault:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>
#include <malloc.h>
#include <errno.h>
#include <string.h>

struct _version {
    int major;
    int minor;
}version;

char *inputName;
char *outputName;
char **outputBuffer;
int length;
void init() {
    inputName=outputName=0;
    outputBuffer = NULL;
    length = 0;
    version.major = 0;
    version.minor = 1;

}
void usage(const char *s) {
    printf("Usage: %s -i <input file> -o <output file>\n",s);
    printf("\t %s -h:\t prints this help\n",s);
    printf("\t %s -v:\t prints version\n",s);

}
bool parseArgs(int argc, char * const argv[]) {
    char ch;
    char i=0;
    if(argc < 2) {
        usage(argv[0]);
        return false;
    }
    while ( (ch = getopt(argc,argv,"hvi:o:")) != -1) {
        switch(ch) {
            case 'v':
                printf("Version %d.%d\n", version.major,version.minor);
                return false;
            break;
            case 'i':
                inputName = malloc(strlen(optarg)+1);
                if(errno == ENOMEM) {
                    exit(ENOMEM);
                }
                strcpy(inputName,optarg);
                i++;
            break;
            case 'o':
                outputName = malloc(strlen(optarg)+1);
                if(errno == ENOMEM) {
                    exit(ENOMEM);
                }
                strcpy(outputName,optarg);
                i++;
            break;
            case 'h':
            default:
                usage(argv[0]);
                return false;
            break;

        }   
    } 
    return(i==2);   
}
bool processFile() {
    printf("trying input:%s\toutput:%s\n",inputName,outputName);
    FILE *inf = fopen(inputName,"r");
    if(!inf) {int e=errno;perror(inputName); exit(e);}

    char line[1024];        
    while(fgets(line,1024,inf)){
        if(strnlen(line,1024)==1024) exit(255);
        printf("next line read(line length is %d):%s\n", strnlen(line,1024), line);
        outputBuffer = realloc(outputBuffer,(++length)*sizeof(char *));
        printf("reallocation bytes requested:%d outputBuffer=0x%0X\n",length*sizeof(char *),outputBuffer);
        outputBuffer[length-1] = malloc(strnlen(line,1024)*sizeof(char)+1);
        strncpy(outputBuffer[length-1],line,1024);
        printf("---------------------------------------------\n");
        int i;
    }
    if(!feof(inf)){
        printf("failed reading %s:%d error:%d", inputName, length,ferror(inf));
        exit(ferror(inf));
    }


    if(inf) fclose(inf);
    return false;
}
bool writeOutput() {
    FILE *outf = fopen(outputName,"w");
    if(!outf) {int e=errno;perror(outputName); exit(e);}

    if(outf) fclose(outf);  
    return false;
}
void finish() {
    if(inputName) free(inputName);
    if(outputName) free(outputName);
}


int main(int argc, char * const argv[]){
    init();
    bool ok = parseArgs(argc, argv);
    if(ok) {
        ok = processFile();
        if(ok) {
            if(writeOutput()) {
                printf("Success.\n");
            }       
        }
        else { 
            printf("error processing file\n");
        }
    }

    finish();
}

任何帮助将不胜感激!

阅读注释后添加代码示例和 valgrind 输出:

next line read(line length is 32):libqosadaptor libqosadaptor.%::

reallocation bytes requested:8 outputBuffer=0x4C4F360 ==8347== Invalid write of size 1 ==8347== at 0x4A095CC: strncpy (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==8347== by 0x400DFC: processFile (makefileUpgrade.c:83) ==8347== by 0x400F76: main (makefileUpgrade.c:113) ==8347== Address 0x4c4f3d1 is 0 bytes after a block of size 33 alloc'd ==8347== at 0x4A0645D: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==8347== by 0x400DC4: processFile (makefileUpgrade.c:82) ==8347== by 0x400F76: main (makefileUpgrade.c:113)

--------------------------------------------- next line read(line length is 87): $(SHOW) $(MAKE) $(MAKEOPTS) REL_DIR=adaptor/qos -C $(ROOT)/adaptor/qos $* -f makefile

valgrind: m_mallocfree.c:277 (mk_plain_bszB): Assertion 'bszB != 0' failed. valgrind: This is probably caused by your program erroneously writing past the end of a heap block and corrupting heap metadata. If you fix any invalid writes reported by Memcheck, this assertion failure will probably go away. Please try that before reporting this as a bug.

==8347== at 0x3805028C: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x380503E6: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x3805AA4A: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x3805C9B7: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x38021865: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x3809C5C2: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux) ==8347== by 0x380AB21C: ??? (in /usr/lib64/valgrind/memcheck-amd64-linux)

sched status: running_tid=1

Thread 1: status = VgTs_Runnable ==8347== at 0x4A083AA: realloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==8347== by 0x400D54: processFile (makefileUpgrade.c:80) ==8347== by 0x400F76: main (makefileUpgrade.c:113)

最佳答案

解决方案很简单,但很棘手(我的错误是没有读完手册页):

strncpy 有错误,因为它总是写入 n 个字节。

strncpy(outputBuffer[length-1],line,1024);

源字符串比 malloc 的大小更大,而 violla 是典型的溢出。

char *strncpy(char *dest, const char *src, size_t n);

If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.

关于c - C 中的 realloc 字符串表在第四次迭代时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25698760/

相关文章:

java - Java 和 .NET 字符串文字驻留在哪里?

c - 如何用C语言将棋盘内容显示为字符串并将字符串存储在表中?

c - c89 中的指示符

c - 如何通过 C 中的函数初始化多个未知大小的数组

c - realloc 指针指向随机内存,导致程序崩溃

c - 我该怎么做才能导致 realloc 停止工作?

c - VS 2010 中 realloc 的奇怪错误

c - C 中 malloc() 的一些有用示例是什么?

C - exec 执行带有参数的命令?

c - 删除功能是否保证删除文件?