kubisztal Ответов: 2

Поиск неисправности сегментации


Я хотел бы узнать ваше мнение о том, как определить проблему ошибки сегментации в моем коде, написанном на языке Си. Я бы поделился своим кодом для ваших ценных комментариев,

С уважением

Что я уже пробовал:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <signal.h>
#include <assert.h>
#include <hiredis/hiredis.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>
#include <event.h>
#include <unistd.h>
#include <time.h>
#include <stdbool.h>
#define PACKETSIZE sizeof(cloudRANMessage)
#define COMMANDSIZE 256
 
typedef struct cloudRANMessage
{
    unsigned int      station_id;
    unsigned int      location_area;
    unsigned int      counterRedis;
    char              clientHostName[1024];
    char              command[COMMANDSIZE];
 
}cloudRANMessage;
 
char *accessKey;
char *accessHash;
 
void callbackDeserialize();
void serialize();
 
void printMyMessage(cloudRANMessage *message)
{
    printf("%d\n", message->location_area);
    printf("%d\n", message->station_id);
    printf("%s\n", message->command);
    printf("%s\n", message->counterRedis);
    printf("%s\n", message->clientHostName);
}
 
void serialize(cloudRANMessage *message, char *data)
{
    assert(data != NULL);
    memcpy(data, message, sizeof *message);
}
 
 
void deserialize(char *data, cloudRANMessage *tempMessage)
{
    memset(tempMessage, 0, sizeof(cloudRANMessage));
    memcpy(tempMessage, data, sizeof(cloudRANMessage));
    printMyMessage(tempMessage);
}
 
void deserializeLocal(char *data, cloudRANMessage *tempMessageLocal)
{
    memset(tempMessageLocal, 0, sizeof(cloudRANMessage));
    memcpy(tempMessageLocal, data, sizeof(cloudRANMessage));
    printMyMessage(tempMessageLocal);
}
 
void getCallback(redisAsyncContext *c, void *r, void *privdata)
{
    redisReply *reply = r;
    printf("%s\n", reply->str);                   // Call deserializaton function for the data retrieval.;
    /* Disconnect after receiving the reply to GET */
    redisAsyncDisconnect(c);
}
 
void replyParsing(void *reply)  // Parsing will be used to handle subscripton message reply to get the hash-key pair of the data that is written.
{
    redisReply *parsing = reply;
    printf("parsing array %s", parsing->element[2]->str);
    char *parsingArray = parsing->element[2]->str;
    char *p;
    p = strtok(parsingArray,"[ ""].");
    int i= 0;
    while(p !=NULL)
    {
        p = strtok(NULL,"[ ""].");
        if(i == 7)
        {
            accessHash = p;
            printf("%s\n",p);
        }
        else if(i == 8)
        {
            accessKey = p;
            printf("%s\n",p);
        }
    i++;
    }
     // send pointer here !
    // GET command here with the appropiate keys
}
// for the key hash value in the char. [8&9]
 
void listenChannel(redisAsyncContext *c, void *reply, void *privdata)
{
    struct event_base *base = (struct event_base*)privdata;
    char isExists = malloc(sizeof(isExists));
    isExists = "eNB";
    bool executeParsing = false;
    redisReply *r = reply;
    if (reply == NULL)
    return;
 
    printf("Client successfully subscribed to channel !\n");
    if(r->type == REDIS_REPLY_ARRAY){
 
        for(int j =0; j<r->elements;j++)
        {
            printf("Printing Redis Reply: %u) %s\n",j,r->element[j]->str);
            if (strstr(r->element[j]->str,isExists) != NULL)
                executeParsing = true;
            else
                executeParsing = false;
        }
 
    }
        if (executeParsing){
        replyParsing(r);
        printf("test received key !\n");
        event_base_loopexit(base,NULL);
    }
        else
        event_base_loopcontinue(base);
}
 
void callbackDeserialize(redisAsyncContext *c, void *r, cloudRANMessage *tempMessage) {
    redisReply *reply = r;
    if (reply == NULL) return;
    printf("%s\n", reply->str);                   // Call deserializaton function for the data retrieval.
    char *stringReply = reply->str;
    deserialize(stringReply, tempMessage);
    /* Disconnect after receiving the reply to GET */
    //
}
 
void callbackDeserializeLocal(redisAsyncContext *c, void *r, cloudRANMessage *tempMessageLocal) {
    redisReply *reply = r;
    if (reply == NULL) return;
    printf("%s\n", reply->str);                   // Call deserializaton function for the data retrieval.
    char *stringReply = reply->str;
    deserializeLocal(stringReply, tempMessageLocal);
    /* Disconnect after receiving the reply to GET */
    //
}
 
 
void connectCallback(const redisAsyncContext *c, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c->errstr);
        return;
    }
    printf("Connected...\n");
}
 
void disconnectCallback(const redisAsyncContext *c, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c->errstr);
        return;
    }
    printf("Disconnected...\n");
 
}
 
void connectCallback2(const redisAsyncContext *c2, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c2->errstr);
        return;
    }
    printf("Connected...\n");
}
 
void disconnectCallback2(const redisAsyncContext *c2, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c2->errstr);
        return;
    }
    printf("Disconnected...\n");
 
}
void connectCallback3(const redisAsyncContext *c3, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c3->errstr);
        return;
    }
    printf("Connected...\n");
}
 
void disconnectCallback3(const redisAsyncContext *c3, int status) {
    if (status != REDIS_OK) {
        printf("Error: %s\n", c3->errstr);
        return;
    }
    printf("Disconnected...\n");
 
}
 
void exitCallback(redisAsyncContext *c, void *reply, void *privdata){
 
    struct event_base *base = (struct event_base*)privdata;
    event_base_loopexit(base,NULL);
}
 
int main (int argc, char **argv) {
 
    cloudRANMessage *cloudRANptr = malloc(sizeof(cloudRANMessage));
    cloudRANMessage *receivedMsg = malloc(sizeof(cloudRANMessage));
    cloudRANMessage *initialMessage = malloc(sizeof(cloudRANMessage));
    void *data = calloc(1,sizeof(cloudRANMessage));
 
    accessKey = malloc(sizeof(char));
    accessHash = malloc(sizeof(char));
 
    struct timeval start;
 
    initialMessage->location_area = 7214;
    initialMessage->station_id = 45632;
    initialMessage->counterRedis = 0;
    gethostname(initialMessage->clientHostName,1023);
    strcpy(initialMessage->command, "HANDOVER\0");
    gethostname(initialMessage->clientHostName,1023); // Gets the hostname of the compiled computer and puts in struct.
    printf("%s\n",initialMessage->clientHostName);
 
        signal(SIGPIPE, SIG_IGN);
        struct event_base *base = event_base_new();
        struct event_base *base3 = event_base_new();
        struct event_base *base2 = event_base_new();
        struct event_base *base4 = event_base_new();
 
        redisAsyncContext *localCon = redisAsyncConnect("localhost", 6379); // Connection will be used for get operation
        if (localCon->err) {
        printf("Error on localhost connection: %s\n", localCon->errstr);
        return 1;
        }
 
        redisAsyncContext *clientCon = redisAsyncConnect("192.168.1.103", 6379); // Connection will be used to write data on master
        if (clientCon->err) {
        printf("Error on master connection: %s\n", clientCon->errstr);
        return 1;
        }
 
        redisAsyncContext *subCon = redisAsyncConnect("localhost", 6379); // Connection will be used for SUBSCRIBE & UNSUBSCRIBE command
        if (subCon->err) {
        printf("Error on subscribe connection: %s\n", subCon->errstr);
        return 1;
        }
        unsigned int counter = malloc(sizeof(unsigned int));
        counter = 0;
 
        redisLibeventAttach(subCon, base2);
 
        redisAsyncSetConnectCallback(subCon,connectCallback3);
        redisAsyncSetDisconnectCallback(subCon,disconnectCallback3);
        counter++;
        redisAsyncCommand(subCon,listenChannel,base2,"SUBSCRIBE cloudRAN");
        WAITSUBSCRIBE:
        event_base_dispatch(base2);
        //initialize data on master !
        serialize(initialMessage,data);
        redisLibeventAttach(clientCon,base4);
        // Should run once to set the data !
        redisAsyncCommand(clientCon,exitCallback,base4,"HSET TA_1 eNB_1 %b",data,sizeof(cloudRANMessage));
 
        event_base_dispatch(base4);
 
        if(counter != 1){
        redisLibeventAttach(localCon, base);
        redisAsyncSetConnectCallback(localCon,connectCallback);
        redisAsyncSetDisconnectCallback(localCon,disconnectCallback);
        // Make an initial SET operation to the MASTER !
        // Access the data locally
 
        redisAsyncCommand(localCon,callbackDeserialize,receivedMsg,"HGET %s %s",accessHash,accessKey);
        printf("Execution in UNIX time for HGET:%ld\n", (start.tv_sec * 1000000 + start.tv_usec));
        event_base_loop(base,EVLOOP_ONCE);
        printf("Hash and Key value %s %s",accessHash,accessKey);
 
         if(initialMessage->clientHostName != receivedMsg->clientHostName){
 
            redisLibeventAttach(clientCon, base3);
 
            redisAsyncSetConnectCallback(clientCon,connectCallback2);
            redisAsyncSetDisconnectCallback(clientCon,disconnectCallback2);
 
            cloudRANptr = receivedMsg;   // Now access and change the data after verification
            cloudRANptr->counterRedis++;
            cloudRANptr->location_area= 56789; // Assign arbitrary location area value on this client
            serialize(cloudRANptr,data); // try with a different data pointer as well !!
            gettimeofday(&start, NULL);
            printf("Execution in UNIX time for HSET:%ld\n", (start.tv_sec * 1000000 + start.tv_usec));
            redisAsyncCommand(clientCon,exitCallback,base3,"HSET %s %s %b",accessHash,accessKey,data,sizeof(cloudRANMessage));
 
            event_base_dispatch(base3);
            goto WAITSUBSCRIBE;
        }
    }
        else
        goto WAITSUBSCRIBE;
    //redisAsyncCommand(c,NULL, NULL, "PUBLISH cloudRAN %b", data, sizeof(cloudRANMessage));
    return 0;
}

2 Ответов

Рейтинг:
9

Patrice T

Я бы ожидал isExists чтобы быть указателем

char isExists = malloc(sizeof(isExists));


Используйте отладчик, он позволит вам увидеть, где находится Segfaultabd для проверки переменных, тогда у вас будет представление о том, что происходит.

Существует инструмент, который позволяет вам видеть, что делает ваш код, его имя отладчик Это также отличный инструмент обучения, потому что он показывает вам реальность, и вы можете увидеть, какие ожидания соответствуют реальности.
Когда вы не понимаете, что делает ваш код или почему он делает то, что делает, ответ таков: отладчик.
Используйте отладчик, чтобы увидеть, что делает ваш код. Просто установите точку останова и посмотрите, как работает ваш код, отладчик позволит вам выполнять строки 1 на 1 и проверять переменные по мере их выполнения.

Отладчик-Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010-YouTube[^]
Отладчик здесь для того, чтобы показать вам, что делает ваш код, и ваша задача-сравнить его с тем, что он должен делать.
В отладчике нет никакой магии, он не находит ошибок, он просто помогает вам. Когда код не делает того, что ожидается, вы близки к ошибке.


Рейтинг:
13

Jochen Arndt

Это слишком много кода, чтобы проверять его на наличие недопустимых указателей и индексов.

Здесь есть две ошибки:

accessKey = malloc(sizeof(char));
accessHash = malloc(sizeof(char));
Вы, вероятно, хотите использовать sizeof(char*) вместо.
[РЕДАКТИРОВАТЬ]
Или вообще не выделяйте, когда назначаете только указатели.

Здесь есть еще одна ошибка:
printf("%s\n", message->counterRedis);
Вы должны использовать "%d", потому что message->counterRedis иметь тип int.
[/РЕДАКТИРОВАТЬ]

Некоторые подсказки для поиска и / или обнаружения таких ошибок:

Вы должны добавить assert операторы для проверки всех параметров указателя функции на отсутствие NULL.
Пример (где у вас уже был один чек):
void serialize(cloudRANMessage *message, char *data)
{
    assert(message != NULL);
    assert(data != NULL);
    memcpy(data, message, sizeof *message);
}

Вы должны инициализировать все переменные. Пример:
char *accessKey = NULL;
char *accessHash = NULL;

Это также может помочь добавить параметр длины в функции:
void serialize(cloudRANMessage *message, char *data, size_t data_buf_len)
{
    assert(message != NULL);
    assert(data != NULL);
    assert(data_buf_len >= sizeof(*message));
    memcpy(data, message, sizeof *message);
}

[РЕДАКТИРОВАТЬ]
Компилировать также со всеми включенными предупреждениями (-Wall для большинства компиляторов). Это может привести к некоторым несоответствиям типов данных.
[/РЕДАКТИРОВАТЬ]

Если у вас все еще есть нарушения доступа, вы должны использовать отладчик и пройти через свой код.