Таблица строк realloc в C вылетает на 4-й итерации
Хотя здесь было несколько ответов относительно этой проблемы: я все еще не мог вписать их в следующий код, так как segfault
на 4th iteration
processFile:
#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== в 0x4A095CC: strncpy (в /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so= = 8347) 0x400DFC: processFile (makefileUpgrade.c:83) ==8347== 0x400F76: main (makefileUpgrade.c:113) ==8347== Адрес 0x4c4f3d1 равен 0 байтов после блока размером 33 alloc'd ==8347== в 0x4A0645D: malloc (в /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==8347== по 0x400DC4: processFile (makefileUpgrade.c:82) ==8347== по 0x400F76: main (makefileP: 113)
--------------------------------------------- читать следующую строку (строка длина составляет 87): $(SHOW) $(MAKE) $(MAKEOPTS) REL_DIR= адаптер /qos -C $(ROOT)/ адаптер /qos $* -f make-файл
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: realloc (в /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==8347== по 0x400D54: processFile (makefileUpgrade.c:80): 8347 == по 0x400F76: main (makefileUpgrade.c: 113)
1 ответ
Решение было простым, но хитрым (и моя вина не была в том, чтобы прочитать страницу руководства до конца):
виноват strncpy, поскольку он всегда записывает n байтов.
strncpy(outputBuffer[length-1],line,1024);
исходная строка была больше, чем размер malloc, и имела классическое переполнение.
char * strncpy (char * dest, const char * src, size_t n);
Если длина src меньше n, strncpy() записывает дополнительные нулевые байты в dest, чтобы обеспечить запись всего n байтов.