草庐IT

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

coder 2024-06-12 原文

所以我正在构建一个虚拟机,并试图让它尽可能跨平台,突然遇到一个奇怪的错误。我的机器有一个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 时)你调用 getFirstFree(*m) memallocate开头,但是看这个函数:

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

m.memory[i].acquired 对于 0number_of_instructions_in_your_input_file - 1 之间的 i 都是相等的在 writeInstruction 中将它们初始化为 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;
}

编辑:

首先关于您的评论:

By default, the members of the structure is initialised as 0

这不是真的!

现在谈谈为什么在没有 malloc 的情况下出现段错误,以及它如何与 valgrind 的警告相关联。

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

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

对于任何 add m.memory[add].acquired 很可能不同于 0,所以一旦 add 等于 NUM_MEM 你有段错误。

为什么 malloc 没有发生这种情况?仅仅因为您很幸运(但不是运气),您的堆比堆栈“干净”。为什么它只发生在 Windows 中?因为这次你没那么幸运(我什至在 Windows 中都没有段错误)。

关于c - 在 C 中调用函数时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45742464/

有关c - 在 C 中调用函数时出现段错误的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  3. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  6. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  7. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  8. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  9. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  10. ruby-on-rails - 错误 : Error installing pg: ERROR: Failed to build gem native extension - 2

    我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby​​'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe

随机推荐