前一段排查产品的一个异常问题,是有关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
您的支持是对博主最大的鼓励👍,感谢您的认真阅读。
本博客持续更新,欢迎您关注和交流!
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。