前一段排查产品的一个异常问题,是有关C++ string类的,做字符串赋值操作时,应用程序崩溃了。

堆栈信息如下:

 

 

经过分析代码,发现同一个字符串变量会在多个线程里做赋值操作,而且没有加锁保护。

string类字符串赋值操作是线程不安全的,当多个线程同时对同一个string类变量做赋值操作时,就会产生异常。

 

一般来说,声明string变量时(不做赋值,或者字符串长度为0),string对象内会有一个保存字符串的地址,其内存长度为0;

当再次赋值一个较长字符串时,string对象会重新从堆中分配一段地址存放内容,释放之前声明时产生的内存地址。

先看一个简单的string 初始化例子:

 1 #include <string>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <stdio.h>
 5 
 6 using std::string;
 7 
 8 int main(int argc, const char* argv[])
 9 {
10     string localstr="";
11     if(localstr.empty())
12         printf("localstr empty: %s\n", localstr.c_str());
13 
14    
15    printf("c_str = %p, capacity = %d, size = %d\n", localstr.c_str(), localstr.capacity(), localstr.size());
16    localstr = "hello world!";
17    printf("c_str = %p, capacity = %d, size = %d\n", localstr.c_str(), localstr.capacity(), localstr.size());
18 
19    return 0;
20 }

打印输出:

1 c_str = 0x602028, capacity = 5, size = 5
2 c_str = 0x602058, capacity = 12, size = 12

 

如果是多个线程同时对同一个string对象做赋值操作,在没有任何锁保护情况下,会产生异常。

示例代码核心部分:

 1 string  test_str1;
 2 string    test_str2;
 3 
 4 void *string_test_thread_ex(void *p)
 5 {    
 6     struct sched_param  curr_param;
 7     
 8     prctl(PR_SET_NAME, "string_test");
 9 
10 
11     NUM_PROCS = sysconf(_SC_NPROCESSORS_CONF);
12     if(NUM_PROCS == -1)
13     {
14         printf("failed to get cpu nums: %s(%d)\n", strerror(errno), errno);
15         NUM_PROCS = DEF_CPU_NUM;
16     }
17 
18     CPU_ZERO(&cpuset);
19     cpuidx = (curnum++)%NUM_PROCS;
20     CPU_SET(cpuidx, &cpuset);
21     if (pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset))
22     {
23         perror("pthread_setaffinity_np");
24     }
25     while(1)
26     {
27         test_str1 = "hello world1";
28         test_str2 = "hello world2";
29 
30         usleep(50);
31     }
32   
33 }

 

运行结果:

 1 now create the thread:
 2 *** glibc detected *** ./stringtest: double free or corruption (fasttop): 0x00007f8de80009f0 ***
 3 ======= Backtrace: =========
 4 /lib64/libc.so.6(+0x73ee8)[0x7f8dfe281ee8]
 5     0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
 6 /lib64/libc.so.6(cfree+0x6c)[0x7f8dfe286d6c]
 7 /usr/lib64/libstdc++.so.6(_ZNSs9_M_mutateEmmm+0x1c3)[0x7f8dfeaf2a03]
 8 /usr/lib64/libstdc++.so.6(_ZNSs15_M_replace_safeEmmPKcm+0x2c)[0x7f8dfeaf2a3c]
 9 ./stringtest[0x40237a]
10 /lib64/libpthread.so.0(+0x79ed)[0x7f8dfef5b9ed]
11 /lib64/libc.so.6(clone+0x6d)[0x7f8dfe2ea14d]

 

异常堆栈信息和本文开头的不一样,但都是由string对象的并发操作导致APP运行异常。

 

 

参考资料:

https://my.oschina.net/u/4000302/blog/4469522

https://blog.csdn.net/cny901111/article/details/7771668

 

您的支持是对博主最大的鼓励👍,感谢您的认真阅读。

本博客持续更新,欢迎您关注和交流!


本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。