前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >strerror线程安全分析

strerror线程安全分析

作者头像
一见
发布2018-08-10 16:50:59
1.4K0
发布2018-08-10 16:50:59
举报
文章被收录于专栏:蓝天蓝天

strerror线程安全分析.pdf

strerror是否线程安全了?

答案是NO,但它有个线程安全的版本:strerror_r。借助Linux的man,即可看到详情:

代码语言:javascript
复制
#include
char *strerror(int errnum);
int strerror_r(int errnum, char *buf, size_t buflen); /* GNU-specific */

那么,在多线程中使用strerror是否安全了?答案是不一定,一定情况下也是非常安全的。

不安全会造成内存违规访问吗?也就是会发生SIGSEGV吗?答案是NO,仍是内存安全的,但是可能会返回错乱的字符串。

那么,在多线程程序中,什么情况下使用strerror是绝对安全的了?如果参数errnum是一个已知的errno,则使用strerror是绝对安全的,也就是会返回期待的字符串,而不会出现乱码。

对比strerror源码,是因为strerror会在下述直接返回:

代码语言:javascript
复制
if (__builtin_expect (ret != NULL, 1))
return ret;

而这走的是_strerror_r中的分支:

代码语言:javascript
复制
return (char *) _(_sys_errlist_internal[errnum]);

errno是否线程安全?

答案是不一定,取决于编译宏:

代码语言:javascript
复制
#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#   define errno (*__errno_location ())
#  endif

可以通过下段小代码,来确定默认时是否有定义,如果没有,则需要在编译时加上:

代码语言:javascript
复制
#include
int main()
{
#ifdef _GNU_SOURCE
printf("_GNU_SOURCE defined\n");
#else
printf("_GNU_SOURCE not defined\n");
#endif
#ifdef _LIBC_REENTRANT
printf("_LIBC_REENTRANT defined\n");
#else
printf("_LIBC_REENTRANT not defined\n");
#endif
#ifdef _LIBC
printf("_LIBC defined\n");
#else
printf("_LIBC not defined\n");
#endif
return 0;
}

附1:strerror源码

代码语言:javascript
复制
// glibc-2.14\string\strerror.c
#include
/* Return a string describing the errno code in ERRNUM.
The storage is good only until the next call to strerror.
Writing to the storage causes undefined behavior.  */
libc_freeres_ptr (static char *buf);
char *
strerror (errnum)
int errnum;
{
char *ret = __strerror_r (errnum, NULL, 0);
int saved_errno;
if (__builtin_expect (ret != NULL, 1))
return ret;
saved_errno = errno;
if (buf == NULL)
buf = malloc (1024);
__set_errno (saved_errno);
if (buf == NULL)
return _("Unknown error");
return __strerror_r (errnum, buf, 1024);
}

附2:__strerror_r源码

代码语言:javascript
复制
// glibc-2.14\string\_strerror.c
/* Return a string describing the errno code in ERRNUM.  */
char *
__strerror_r (int errnum, char *buf, size_t buflen)
{
if (__builtin_expect (errnum < 0 || errnum >= _sys_nerr_internal
|| _sys_errlist_internal[errnum] == NULL, 0))
{
/* Buffer we use to print the number in.  For a maximum size for
`int' of 8 bytes we never need more than 20 digits.  */
char numbuf[21];
const char *unk = _("Unknown error ");
size_t unklen = strlen (unk);
char *p, *q;
bool negative = errnum < 0;
numbuf[20] = '\0';
p = _itoa_word (abs (errnum), &numbuf[20], 10, 0);
/* Now construct the result while taking care for the destination
buffer size.  */
q = __mempcpy (buf, unk, MIN (unklen, buflen));
if (negative && unklen < buflen)
{
*q++ = '-';
++unklen;
}
if (unklen < buflen)
memcpy (q, p, MIN ((size_t) (&numbuf[21] - p), buflen - unklen));
/* Terminate the string in any case.  */
if (buflen > 0)
buf[buflen - 1] = '\0';
return buf;
}
return (char *) _(_sys_errlist_internal[errnum]);
}
weak_alias (__strerror_r, strerror_r)
libc_hidden_def (__strerror_r)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-04-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • strerror是否线程安全了?
  • errno是否线程安全?
  • 附1:strerror源码
  • 附2:__strerror_r源码
相关产品与服务
Elasticsearch Service
腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档