【问题标题】:Valgrind throwing unexplainable error in threadValgrind 在线程中抛出无法解释的错误
【发布时间】:2016-01-16 22:46:43
【问题描述】:

我无法确定 valgrind 抛出此错误的原因:

==82185== Thread 2:
==82185== Use of uninitialised value of size 8
==82185==    at 0x401B9A: proc_outconnection_thread (station.c:401)
==82185==    by 0x4E3CDF4: start_thread (in /usr/lib64/libpthread-2.17.so)
==82185==    by 0x51471AC: clone (in /usr/lib64/libc-2.17.so)
==82185==
the pass im sending is 'this'
==82185== Use of uninitialised value of size 8
==82185==    at 0x401BCA: proc_outconnection_thread (station.c:403)
==82185==    by 0x4E3CDF4: start_thread (in /usr/lib64/libpthread-2.17.so)
==82185==    by 0x51471AC: clone (in /usr/lib64/libc-2.17.so) 
==82185==

作为一些背景信息,我试图用 C 语言创建的程序模拟了一个使用 TCP 连接作为“火车”的火车站。我正在尝试让程序使用线程来侦听并尝试连接到其他站点(程序的其他实例)。

通过包含指向内部数据结构的指针的参数结构将内部数据结构传递给线程创建函数时,似乎存在问题。这样每个线程都有一个指向程序内部数据的指针。

在我的测试中,该文件是用 gcc -pthread -g -o station station.c -Wall -pedantic -std=gnu99

要产生我的错误,请以 valgrind ./station tom authf logfile 3329 127.0.1.1 开始一个 station 实例 然后用valgrind ./station tim authf logfile 3328 127.0.1.1开始另一个实例

由于 main 中的 if 语句,带有 tim 的站名将尝试连接到 tom,并且 tom 将创建一个套接字并侦听 tims 尝试连接。连接似乎是成功的,但是由于某种原因,我也无法刷新连接以在其间发送任何内容,我感觉这可能是因为 Valgrind 告诉我的。 奇怪的是,当为 tom 实例上的连接创建线程时,尽管创建线程的过程非常相似(相同的参数通过参数指针传递,并且进行了相同的分配),但不会引发 valgrind 中的错误.

这可能是对 tim 结局的误报,还是我在这里做错了什么?

【问题讨论】:

  • 不要链接到源代码。将您的代码分解成可消化的大小,但仍然存在同样的问题,并将其展示给我们。
  • 使用gcc在ubuntu linux 14.04下编译代码,参数-Wall -Wextra -pedantic -std-c99会导致一长串警告信息。强烈建议修复这些警告。关于未使用变量和未使用参数的警告只是马虎编程的标志,但其他警告,例如对某些 fprintf() 调用的错误参数的警告更为严重注意:第 403 和 405 行(在我的编辑器中)包含fprintf() 警告。
  • 发布的代码中有几个magic 号码。 magic 数字使代码更难理解,并且在执行维护时确实令人头疼。强烈建议为这些数字插入一个枚举或#define,并使用有意义的名称,并在整个代码中使用这些有意义的名称。
  • 需要检查 fgets()(和类似的 I/O 语句)的返回值,以确保操作成功。通过套接字进行通信时,正如代码所做的那样,使用send()recv() 比使用fprintf()fgets() 更好
  • 这里是第 405 行和第 407 行的警告:405:5: warning: format not a string literal and no format arguments [-Wfomat-security] fprintf(conStation.clientCon, internal->stationAuth);407:5: warning: format not a string literal and no format arugments [-Wformat-security] fprintf(conStation.clientCon, internal->stationName); 注意:我在文件前添加了 #define _POSIX_SOURCE 以消除关于 fdopen() 的警告,该警告将所有内容移到几行

标签: c multithreading sockets tcp valgrind


【解决方案1】:

跟踪internal 数据结构的值回到它的来源,您将看到它源自未初始化的struct 对象。您稍后将值分配给某些字段,但不是全部。

始终初始化 struct 对象,同时注意您有一个约定,明确说明默认初始化(就像使用 0 完成一样)对类型意味着什么。

如果,有一天,您真的遇到了性能瓶颈,因为您的编译器没有优化未使用的初始化,请重新考虑并采取不同的做法。在这里,因为您正在启动线程并执行其他复杂的事情,所以永远无法衡量差异。

【讨论】:

  • 我已经初始化了我的所有结构(将所有成员设置为 null)并且仍然遇到问题,但是 valgrind 声称它正在读取结构中未初始化的字节。不过你提出了一个很好的观点
【解决方案2】:

您的问题是将局部变量的指针传递给线程函数。最简单的解决方法是将此变量声明为静态或全局变量,但如果有多个线程使用该变量,这并不好。 最好为结构分配所需的内存大小,初始化并将其传递给线程函数:

ArgStruct *argStruct = malloc(sizeof(ArgStruct));
if(argStruct == NULL) {
    fprintf(stderr, "Cant alloc memory!\n");
    exit(98);
}
argStruct->internalStruct = internal;
argStruct->clientCon = fdopen(fd, "r+");
pthread_create(&threadId, NULL, proc_outconnection_thread, (void *)argStruct);

另外,不要忘记释放这段内存(例如在proc_outconnection_thread() 的末尾)。

【讨论】:

  • 非常感谢!这已经解决了问题,我有一个错误的想法,并认为只有一个指向局部变量的指针就足以让其他线程使用它。
猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 2016-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
相关资源
最近更新 更多