c - 在第4次迭代的C崩溃中重新分配字符串表

标签 c realloc string-table

尽管这里有关于此问题的几个答案:我仍然无法使它们适合以下代码,因为它在processFile的segfault上为4th iteration

#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输出:


  下一行读取(行长为32):libqosadaptor libqosadaptor。%::
  
  请求的重新分配字节数:8 outputBuffer = 0x4C4F360
  == 8347 ==大小为1的无效写入
  == 8347 == at 0x4A095CC:strncpy(在/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so中)
  == 8347 ==通过0x400DFC:processFile(makefileUpgrade.c:83)
  == 8347 ==通过0x400F76:main(makefileUpgrade.c:113)
  == 8347 ==在分配了大小为33的块后,地址0x4c4f3d1为0字节
  == 8347 ==在0x4A0645D:malloc(在/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
  == 8347 ==通过0x400DC4:processFile(makefileUpgrade.c:82)
  == 8347 ==通过0x400F76:main(makefileUpgrade.c:113)
  
  ---------------------------------------------下一行读取(第长度为87):$(SHOW)$(MAKE)$(MAKEOPTS)REL_DIR =适配器/ qos -C
  $(ROOT)/适配器/ qos $ * -f makefile
  
  valgrind:m_mallocfree.c:277(mk_plain_bszB):断言'bszB!= 0'
  失败了valgrind:这可能是由于您的程序错误导致的
  写越过堆块的末尾并破坏堆元数据。如果
  您修复了Memcheck报告的所有无效写入,此断言
  失败可能会消失。请在举报之前尝试一下
  作为一个错误。
  
  == 8347 ==在0x3805028C:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x380503E6:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x3805AA4A:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x3805C9B7:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x38021865:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x3809C5C2:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  == 8347 ==通过0x380AB21C:??? (在/ usr / lib64 / valgrind / memcheck-amd64-linux中)
  
  预定状态:running_tid = 1
  
  线程1:状态= VgTs_Runnable
  == 8347 ==在0x4A083AA:重新分配(在/usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so中)
  == 8347 ==通过0x400D54:processFile(makefileUpgrade.c:80)
  == 8347 ==通过0x400F76:main(makefileUpgrade.c:113)

最佳答案

解决方法很简单,但是很棘手(我的错是直到最后都没有阅读手册页):

strncpy存在错误,因为它始终写入n个字节。

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


源字符串要大一些,然后再分配大小,而violla是经典的溢出。


  char * strncpy(char * dest,const char * src,size_t n);
  
  如果src的长度小于n,则strncpy()写入其他null
         要确保写入的字节总数为n个字节。

本文翻译自 https://stackoverflow.com/questions/25698760/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。


相关文章:

c++ - 当内存可用时,Realloc()返回NULL

c++ - 无需复制消息字符串的跨平台消息目录的任何工作代码?

c - 在C中调用Assembly函数,将字符串反向

c - 条件下的Eclipse CDT预处理器get语句

c - 潜在指针问题C编程

c - 是否使用了malloc / realloc / calloc?

c - 具有realloc的动态2D数组会产生分段错误,但可与malloc一起使用

c++ - LoadString()方法在C ++中不起作用

c - 如何在stringtable中增加指针?

c - 中断睡眠后,Cortex M0 +在线程模式下返回错误的位置