Reputation: 1287
Below is the code which I have been using to send data through MQTT on every even index while iterating for loop,
#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. What is missing in the above process that is ending up with segmentation fault? How to resolve this?
Upvotes: 0
Views: 303
Reputation: 59648
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
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. Lets look at your for loop and if statement:
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. 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.
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.
$ 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
Upvotes: 2
Reputation: 1537
I believe you're not malloc
ing enough memory for key
in the middle of main
. 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). In fact, even snprintf
ing a two-digit number overflows the allocation for key
, since there is a trailing \0
appended.
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
.
Fix by doing char *key= (char *)malloc( 8 );
Upvotes: 2