在 C 中调用函数时出现错误



所以我正在构建一个虚拟机,并试图使其尽可能跨平台,突然遇到了一个奇怪的错误。我的机器有一个let指令,它为机器内存中的变量分配内存,并为该变量分配一个值。简而言之,let函数调用getAddress来获取变量的地址。getAddress检查变量是否已定义,并返回地址。如果未定义变量,则getAddress调用memallocate为变量分配内存,并返回地址。以下是函数的定义:

static uint16_t memallocate(Machine *m, char *symbol){
uint16_t allocationAddress = getFirstFree(*m);
SymbolTable *newSymbol = (SymbolTable *)malloc(sizeof(SymbolTable));
newSymbol->symbolName = strdup(symbol);
newSymbol->next = NULL;
newSymbol->mema = allocationAddress;
if(m->symbolTable==NULL){
m->symbolTable = newSymbol;
}
else{
SymbolTable *temp = m->symbolTable;
while(temp->next!=NULL)
temp = temp->next;
temp->next = newSymbol;
}
m->memory[allocationAddress].acquired = 1;
m->memory[allocationAddress].data.value = 0;
m->occupiedAddress++;
return allocationAddress;
}
uint16_t getAddress(Machine *m, char *symbol){
SymbolTable *table = m->symbolTable;
while(table!=NULL){
if(strcmp(symbol, table->symbolName)==0){
return table->mema;
}
table = table->next;
}
uint16_t address = memallocate(m, symbol); // Here is the segfault happening
return address;
}

这段代码在 Linux 上编译和运行得很好,但在 Windows 上,我在memallocate调用中遇到了段错误。由于memallocate直接传递了getAddress的参数,并且参数都是指针,因此它们不应该改变。但是在通过 CLion 进行调试时,我看到了对memallocate调用的胡言乱语参数,这表明某种堆栈违规(可能是(。同样,它只发生在Windows中。谁能告诉我我的代码出了什么问题? 该项目的完整代码可以在GitHub上找到。

我拿了你的代码,并通过valgrind在linux上运行它:

==13768== Conditional jump or move depends on uninitialised value(s)
==13768==    at 0x109ABE: getAddress (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x10B714: let (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x109425: run (in /home/vonaka/VirtualMachine/machine)
==13768==    by 0x109F64: main (in /home/vonaka/VirtualMachine/machine)
==13768==  Uninitialised value was created by a heap allocation
==13768==    at 0x4C2BE7F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd
==13768==    by 0x109C2F: main (in /home/vonaka/VirtualMachine/machine)
==13768== 

所以(对我们来说幸运的是(这不是Windows特定的问题。诀窍是,在第一次调用getAddress时(当m->symbolTableNULL时(,您在memallocate开头调用getFirstFree(*m),但看看这个函数:

static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while(m.memory[add].acquired)
add++;
return add;
}

0number_of_instructions_in_your_input_file - 1之间的im.memory[i].acquiredwriteInstruction中初始化它们时都等于 1,但m.memory[number_of_instructions_in_your_input_file].acquired尚未初始化。

因此,这样的事情将解决您的问题:

void writeInstruction(Machine *m, uint16_t add, Instruction ins) {
m->memory[add].acquired = 1;
m->memory[add].type = INSTRUCTION;
m->memory[add].data.instruction = ins;
m->occupiedAddress++;
if(add + 1 < NUM_MEM)
m->memory[add + 1].acquired = 0;
}

或者也许这更优雅(如果它有效(:

static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while (m.memory[add].acquired && add < m.occupiedAddress)
add++;
return add;
}

编辑:

首先关于您的评论:

默认情况下,结构的成员初始化为 0

这不是真的!

现在谈谈为什么你有没有malloc的段错误,以及它与瓦尔格林德的警告有什么联系。

堆栈中有Machine类型的变量m和一些其他变量,m包含Cell memory[NUM_MEM],并且每个Cell中都有acquired(未初始化!您的输入文件包含 88 条指令,因此前 88 条acquired将在 88 次writeInstruction调用后正确初始化。然后程序开始通过调用一些函数来执行您的指令,包括memallocategetFirstFree。在此循环中:

while(m.memory[add].acquired)
add++;

对于任何addm.memory[add].acquired很可能与 0 不同,因此一旦add等于NUM_MEM,您就有段错误。

为什么malloc没有发生?仅仅因为你很幸运(但这不是一个好运气(,你的堆比堆栈"干净"。为什么它只发生在Windows中?因为这次你没有那么幸运(即使在 Windows 中我也没有段错误(。

相关内容

  • 没有找到相关文章

最新更新