c语言 - INI 解析器在打开多个部分后因"分段错误"而崩溃



我正在制作一个INI解析器,它将把所有部分保存在数组中供以后使用。我遇到的问题是SECTION_OPEN.我调用ini_init(),这会导致函数的第一行崩溃并显示Segmentation Fault。我以在我的代码中放置许多内存泄漏而闻名,但在浏览之后,我还没有找到解决这个问题的方法。 我试过:

  • 给许多不同的malloc超过100000使用,但仍然崩溃
  • 注释掉代码并慢慢取消注释以查看崩溃的内容

测试.ini:

; This is a valid comment
; Global variables work
var = 1
var2 = 2
var3 = 3
[Test1] ; Section
name = Primitive
organization = PrimOS
test = var
another = test
once_again=another_test
; Will check to see if variables work as intended
[.Test2] ; Subsection
; This variable will crash
another_organization = %name%
; This test will crash
[Test3] ; Section
another_name = "This is me"

伊尼·

#ifndef SEAWARE_INI_H
#define SEAWARE_INI_H
#define MAX_HOLDING_CELL 255
#define MAX_LINE_LENGTH 255
// Syntax
#define QUOTES '"'
#define SECTION_OPEN '['
#define SUBSECTION '.'
#define SECTION_CLOSE ']'
#define VARIABLE_CALL '%'
#define COMMENT ';'
#define EQUALS '='
#define EQUALS_PTR "="
// Only one variableType for each variable
struct variable {
char * variableName;
char * value;
};
// The magic...
struct INI {
// If NULL, you are global
char * sectionName;
// Like [.Test] or [Test1.Test]
struct INI ** subSections;
// Self explanitory
struct variable ** variables;
int subSectionsPtr;
int variablesPtr;
struct INI * nextSection;
struct INI * prevSection;
};
struct INI * ini_init();
struct INI * interpret(struct INI * ini, char * filePath);
#endif

ini.c

#include <ini.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
// Global functions
// Sets up new struct INI * variable
struct INI * ini_init() {
// Crashes
struct INI * newINI = malloc(sizeof(struct INI));
newINI->variablesPtr = 0;
newINI->subSectionsPtr = 0;
newINI->variables = malloc(sizeof(struct variable*)*(newINI->variablesPtr+1));
newINI->subSections = malloc(sizeof(struct INI *)*(newINI->subSectionsPtr+1));
*newINI->variables = NULL;
*newINI->subSections = NULL;
newINI->sectionName = NULL;
newINI->nextSection = NULL;
newINI->prevSection = NULL;
return newINI;
}
// Interprets an INI file, with syntax defined in ../include/ini.h
struct INI * interpret(struct INI * ini, char * filePath) {
// Loop Variables    
char line[MAX_LINE_LENGTH];
FILE * iniFile = fopen(filePath, "r");
bool isSubsection = false;
// Read line by line
while(fgets(line, sizeof(line), iniFile)) {
bool isComment = false;
bool isQuoted = false;
// A holding cell for all the bad defaults out there, stay safe out there...
char holdingCell[MAX_HOLDING_CELL];
int holdingCellPtr = 0;
// For each character in line
for (int i = 0; i < strlen(line); i++) {
printf("%c", line[i]);
// Prevents memory leaks in holdingCell
holdingCell[holdingCellPtr] = '';
// Interpret
switch(line[i]) {
// Move into section
case SECTION_OPEN: {
// If you are in a subsection, get out of it
if (isSubsection == true) {
ini = ini->prevSection;
isSubsection = false;
}
struct INI * newSection = ini_init();
if (line[(i+1)]==SUBSECTION) {
isSubsection = true;
// Reallocate size of subSections array
ini->subSections =  realloc(ini->subSections, sizeof(struct INI *) * (ini->subSectionsPtr+1));

// Set new subsection and enter it
newSection->prevSection = ini;
ini->subSections[ini->subSectionsPtr] = newSection;
ini->subSectionsPtr++;
ini = ini->subSections[ini->subSectionsPtr];
i++;
}
else {
// Create new section and go into it
newSection->prevSection = ini;
ini->nextSection = newSection;
ini = ini->nextSection;
ini->nextSection = NULL;
}
break;
}
// Set sectionName
case SECTION_CLOSE: {
ini->sectionName = malloc(sizeof(char) * strlen(holdingCell));
strcpy(ini->sectionName, holdingCell);
break;
}
// Creates new variable and assigns name and value
case EQUALS: {
isQuoted = true;
struct variable * newVar = malloc(sizeof(struct variable)*(ini->variablesPtr+6));
char * value = strtok(line, EQUALS_PTR);
// Set variableName
newVar->variableName = malloc(sizeof(char)*strlen(value));
strcpy(newVar->variableName, value);
// After EQUALS
value = strtok(NULL, EQUALS_PTR);
// Set value
newVar->value = malloc(sizeof(char)*strlen(value));
strcpy(newVar->value, value);

printf("%s", value);
// Add variable to ini field
ini->variables = realloc(ini->variables, sizeof(struct variable*)*(ini->variablesPtr+1));
ini->variables[ini->variablesPtr] = newVar;
ini->variablesPtr++;
break;
}

// Skips to new line
case COMMENT: {
isComment = true;
break;
}

// Gets names and values
default: {
holdingCell[holdingCellPtr] = line[i];
holdingCellPtr++;
break;
}
}
if (isComment == true || isQuoted == true)
break;
}
}
// Stop reading file
fclose(iniFile);
// Loop back to beginning
while(ini->prevSection != NULL) {
ini = ini->prevSection;
}
// You get what you get, stop throwing a fit
return ini;
}

有几个malloc调用strlen.
strlen不计算终止零.
strcpy复制终止零。由于分配的内存不包括终止零,因此在分配之外写入。某些东西被损坏了.
这可以通过分配strlen() + 1来修复 例如

newVar->value = malloc(sizeof(char)*strlen(value));  

应该是

newVar->value = malloc(sizeof(char)*(strlen(value) + 1));  

由于sizeof(char)总是1

newVar->value = malloc(strlen(value) + 1);  

也可以使用。

另一个问题是

// Reallocate size of subSections array
ini->subSections =  realloc(ini->subSections, sizeof ( ini_t*) * (ini->subSectionsPtr+1));
// Set new subsection and enter it
newSection->prevSection = ini;
ini->subSections[ini->subSectionsPtr] = newSection;
ini->subSectionsPtr++;
ini = ini->subSections[ini->subSectionsPtr];
i++;

使用(ini->subSectionsPtr+1)重新分配ini->subSections,使ini->subSectionsPtr成为ini->subSections.
ini->subSectionsPtr++之后的最后一个索引,索引超出分配范围。

ini->subSectionsPtr++;向下移动一行,因此它就在i++;似乎可以解决此问题之前。

最新更新