简体   繁体   English

C - 如何在 function 调用后释放指针时解决分段错误?

[英]C - How to resolve a segmentation fault while freeing the pointer after the function call?

Below is the code which I have been using to send data through MQTT on every even index while iterating for loop,下面是我在迭代 for 循环时用于通过 MQTT 在每个偶数索引上发送数据的代码,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"
#include <jansson.h>

char* s; 

void sendMQTT(char *s){
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc;

    MQTTClient_create(&client, "tcp://localhost:1883", "client-pub",
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }

    pubmsg.payload = s;
    pubmsg.payloadlen = (int)strlen(s);   
    pubmsg.qos = 1;
    pubmsg.retained = 0;
    
    MQTTClient_publishMessage(client, "mqtt-ex", &pubmsg, &token);
    rc = MQTTClient_waitForCompletion(client, token, 10000L);
    // printf("Message with delivery token %d delivered\n", token);
    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    // return rc;
    // return 0;
}


int main() {  
    json_t *root = json_object();
    char myNum[10] = {10, 20, 10, 40, 10, 60, 10, 80, 10, 100};
    
    for(int i=0; i<10;i++)
    {
        if(i%2==0)
        {
            // sendMQTT(s);
            free(s);
            json_decref(root);
            json_t *root = json_object();
        }

    char *key= (char*)malloc(2);
    snprintf(key, sizeof(key), "%d", myNum[i]);

    json_object_set_new( root, key, json_integer(i));      
    
    char *s= (char*)malloc(100);
    s = json_dumps(root, 0);
    printf("s ::  %s\n", s);
    free(key);    
    // puts(s);  
  }  
}

The above code produces the expected result like below,上面的代码产生如下的预期结果,

s ::  {"10": 0}
s ::  {"10": 0, "20": 1}
s ::  {"10": 2}
s ::  {"10": 2, "40": 3}
s ::  {"10": 4}
s ::  {"10": 4, "60": 5}
s ::  {"10": 6}
s ::  {"10": 6, "80": 7}
s ::  {"10": 8}
s ::  {"10": 8, "100": 9}

Whereas, when i invoke the sendMQTT function on every even index, the process is ending up with segmentation fault.然而,当我在每个偶数索引上调用 sendMQTT function 时,该过程以分段错误告终。 What is missing in the above process that is ending up with segmentation fault?上述过程中缺少什么导致分段错误? How to resolve this?如何解决这个问题?

I believe you're not malloc ing enough memory for key in the middle of main .我相信你不是malloc ing 足够 memory 在main中间的key You malloc two bytes, but then you snprintf a number that could be as large as 4 bytes (when n is 9 and myNum is 100).malloc两个字节,但是你snprintf一个可能大到 4 个字节的数字(当n是 9 并且myNum是 100 时)。 In fact, even snprintf ing a two-digit number overflows the allocation for key , since there is a trailing \0 appended.事实上,即使是snprintf一个两位数的数字也会溢出key的分配,因为有一个尾随\0附加。

Note that passing sizeof(key) to snprintf does not protect you -- key is a char * , which is probably 4 or 8 bytes, even though only 2 bytes are available to use at *key .请注意,将sizeof(key)传递给snprintf并不能保护您—— key是一个char * ,它可能是 4 或 8 个字节,即使在*key处只有 2 个字节可用。

Fix by doing char *key= (char *)malloc( 8 );通过执行char *key= (char *)malloc( 8 );来修复

It's not failing on the call to free() , if you run it under a debugger you find it fails on line 28 where you try to find the string length to set it as the payload length调用free()并没有失败,如果您在调试器下运行它,您会发现它在第 28 行失败,您尝试查找字符串长度以将其设置为有效负载长度

pubmsg.payload = s;
pubmsg.payloadlen = (int)strlen(s);   <--- HERE
pubmsg.qos = 1;

This is because you never initialise s to be anything before trying to use it.这是因为您在尝试使用它之前从未将s初始化为任何东西。 Lets look at your for loop and if statement:让我们看看你的 for 循环和 if 语句:

for(int i=0; i<10;i++)
{
    if(i%2==0)
    {
        // sendMQTT(s);
        free(s);
        json_decref(root);
        json_t *root = json_object();
    }

 ...

First time round the loop, i = 0 so i % 2 = 0 so we go into the if block.第一次循环, i = 0 所以i % 2 = 0 所以我们 go 进入 if 块。 At this point s is still null because you haven't got to the code under the if block that would try to set it (which is also wrong because you declare a new char *s rather than reuse the original.此时s仍然是 null 因为您还没有找到尝试设置它的 if 块下的代码(这也是错误的,因为您声明了一个新的char *s而不是重用原来的。

The quickest way to work out where things are failing is to build with all the debug tokens enabled and then run it under gdb.找出问题所在的最快方法是在启用所有调试令牌的情况下进行构建,然后在 gdb 下运行它。

$ gcc -g test.c -lpaho-mqtt3c -ljansson -o test
$ gdb ./test
GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-git
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) run
Starting program: /home/hardillb/temp/so/seg/test 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
__strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:62
62  ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
(gdb) where
#0  __strlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:62
#1  0x0000555555554e54 in sendMQTT (s=0x0) at test.c:28
#2  0x0000555555554f5b in main () at test.c:50

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM