C - Как устранить ошибку сегментации при освобождении указателя после вызова функции? - PullRequest
0 голосов
/ 20 июня 2020

Ниже приведен код, который я использовал для отправки данных через MQTT по каждому четному индексу при итерации для l oop,

#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);  
  }  
}

Приведенный выше код дает ожидаемый результат, как показано ниже,

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}

Тогда как, когда я вызываю функцию sendMQTT для каждого четного индекса, процесс завершается ошибкой сегментации. Чего не хватает в приведенном выше процессе, что приводит к ошибке сегментации? Как решить эту проблему?

Ответы [ 2 ]

2 голосов
/ 21 июня 2020

Я считаю, что у вас malloc недостаточно памяти для key в середине main. У вас malloc два байта, но затем вы snprintf число, которое может быть целым 4 байта (когда n равно 9, а myNum равно 100). Фактически, даже snprintf с номером two-di git переполняет выделение для key, поскольку к нему добавляется конечный \0.

Обратите внимание, что передача sizeof(key) в snprintf не защищает вас - key - это char *, что, вероятно, составляет 4 или 8 байтов, хотя только 2 байта доступны для использования в *key.

Исправить, выполнив char *key= (char *)malloc( 8 );

1 голос
/ 21 июня 2020

Это не дает сбоев при вызове free(), если вы запустите его под отладчиком, вы обнаружите, что он не работает в строке 28, где вы пытаетесь найти длину строки, чтобы установить ее как длину полезной нагрузки

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

Это потому, что вы никогда не инициализируете s как что-либо, прежде чем пытаться его использовать. Давайте посмотрим на ваш оператор для l oop и if:

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

 ...

Первый раз округлить l oop, i = 0, поэтому i % 2 = 0, поэтому мы go в if блок. На этом этапе s все еще имеет значение null, потому что у вас нет кода под блоком if, который попытался бы его установить (что также неверно, потому что вы объявляете новый char *s, а не повторно используете оригинал.

Самый быстрый способ выяснить, где что-то не получается, - это построить со всеми включенными токенами отладки, а затем запустить его под 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
...