C - 如何在函数调用后释放指针时解决分段错误?
C - How to resolve a segmentation fault while freeing the pointer after the function call?
下面是我在循环迭代时通过 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);
}
}
上面的代码产生了如下预期的结果,
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 函数时,该过程以分段错误结束。上面以分段错误结束的过程中缺少什么?如何解决?
我相信您 malloc
在 main
的中间 key
没有足够的内存。你 malloc
两个字节,然后你 snprintf
一个可能大到 4 个字节的数字(当 n
是 9 并且 myNum
是 100 时)。事实上,即使 snprintf
一个两位数的数字也会溢出 key
的分配,因为尾随有一个 [=19=]
。
请注意,将 sizeof(key)
传递给 snprintf
并不能保护您——key
是一个 char *
,它可能是 4 或 8 个字节,即使只有 2 个字节字节可用于 *key
.
通过char *key= (char *)malloc( 8 );
修复
它在调用 free()
时没有失败,如果你 运行 它在调试器下你发现它在第 28 行失败,你试图找到字符串长度以将其设置为有效负载长度
pubmsg.payload = s;
pubmsg.payloadlen = (int)strlen(s); <--- HERE
pubmsg.qos = 1;
这是因为您在尝试使用它之前从未将 s
初始化为任何东西。让我们看看您的 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();
}
...
第一次循环,i
= 0 所以 i % 2
= 0 所以我们进入 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
下面是我在循环迭代时通过 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);
}
}
上面的代码产生了如下预期的结果,
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 函数时,该过程以分段错误结束。上面以分段错误结束的过程中缺少什么?如何解决?
我相信您 malloc
在 main
的中间 key
没有足够的内存。你 malloc
两个字节,然后你 snprintf
一个可能大到 4 个字节的数字(当 n
是 9 并且 myNum
是 100 时)。事实上,即使 snprintf
一个两位数的数字也会溢出 key
的分配,因为尾随有一个 [=19=]
。
请注意,将 sizeof(key)
传递给 snprintf
并不能保护您——key
是一个 char *
,它可能是 4 或 8 个字节,即使只有 2 个字节字节可用于 *key
.
通过char *key= (char *)malloc( 8 );
它在调用 free()
时没有失败,如果你 运行 它在调试器下你发现它在第 28 行失败,你试图找到字符串长度以将其设置为有效负载长度
pubmsg.payload = s;
pubmsg.payloadlen = (int)strlen(s); <--- HERE
pubmsg.qos = 1;
这是因为您在尝试使用它之前从未将 s
初始化为任何东西。让我们看看您的 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();
}
...
第一次循环,i
= 0 所以 i % 2
= 0 所以我们进入 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