首页 > 其他分享 >【segmentation fault】std::string析构崩溃

【segmentation fault】std::string析构崩溃

时间:2023-04-06 20:34:09浏览次数:33  
标签:std segmentation string accessToken ret str 崩溃

今天写了一个小工具,运行时发生segmentation fault,现象如下

第一步:review崩溃附近代码,产生疑惑,崩溃的地方居然是变量定义的地方

std::string accessToken;

崩溃在这个地方,我直接懵了,只是变量定义为啥会报错,没有任何思路,打算单步调试。

第二步:单步调试代码,发现并且是定义的时候崩溃,而是当前函数执行完成,释放栈变量的时候崩溃,此时再看崩溃栈,发现也是崩溃在~basic_string()析构函数中

第三步:怀疑是自己对accessToken赋值产生问题,难道是不能将char*赋值给std::string?去网上搜索一下,发现很多文章说char*赋值std::string会崩溃,

我认为是自己对std::string隐式转换使用错误,再想想不对,我对std::string隐式转换用法是正确的。

我开始修改accessToken的赋值,我发现accessToken赋值的字符很少的时候,程序就不会崩溃了,赋值很长的时候就会崩溃。(当时没有想明白,后来就清楚了)

第四步:陷入困境,我只能怪自己不精通c++,于是用c来改写,把accessToken的类型换成char数组,问题得到解决。

第五步:解决完问题后,我继续分析accessToken字符内容少的时候没有问题,而accessToken内容长的时候却会崩溃。我自己写了一个简单的程序,验证了std::string赋值很长的字符串也是没有问题的。此时我想明白了,肯定是我哪个地方内存越界了,引发了这种奇怪的现象,现象越奇怪,说明可能是内存越界引发的BUG

第六步:采取注释法,发现把url操作这段逻辑注释掉就运行正常了,发现url数组操作越界了。如下图

小结:
对于字符串拼接操作,不允许使用sprintf,必须使用snprintf来代替。

int NacosHelper::queryConfiguration(const std::string& dataId, std::string& result)
{
    int ret = 0;
    const char* func = "queryConfiguration";

    std::list <std::string> headers;
    std::string encoding;
    long readTimeoutMs = 300000;
    std::string paramValues;
    char url[256] = { 0 };
    std::string resp;
    std::string accessToken;

    // 1.参数校验
    if (dataId.empty())
    {
        ret = -1;
        fprintf(stderr, "%s invalid parameter\n", func);
        return ret;
    }

    // 2.登录
    ret = this->login(accessToken);
    if (ret)
    {
        ret = -1;
        return ret;
    }

    // 3.请求注册中心

    // 3.1 拼接url
    if (accessToken.empty())
    {
        sprintf(url, "%s/nacos/v1/cs/configs?dataId=%s.%s&group=%s&tenant=%s", 
            this->_host.c_str(), this->_projectName.c_str(), dataId.c_str(), 
            this->_group.c_str(), this->_namespace.c_str());
    }
    else
    {
        sprintf(url, "%s/nacos/v1/cs/configs?dataId=%s.%s&group=%s&tenant=%s&accessToken=%s",
            this->_host.c_str(), this->_projectName.c_str(), dataId.c_str(),
            this->_group.c_str(), this->_namespace.c_str(), accessToken.c_str());
    }

    // 3.2 请求配置中心
    paramValues = "";
    ret = this->_helper->Get(url, headers, paramValues, encoding, readTimeoutMs, result);
    if (ret)
    {
        ret = -1;
        fprintf(stderr, "%s exec curl error .\n", func);
        return ret;
    }

    if (result.empty())
    {
        ret = -1;
        fprintf(stderr, "%s query configuration %s response empty .\n", func, url);
        return ret;
    }

    return ret;
}


int NacosHelper::parseToken(const std::string& body, std::string& accessToken)
{
    int ret = 0;
    const char* func = "parseToken";

    cJSON* pstRoot = NULL;
    cJSON* pstNode = NULL;

    // 1.参数校验
    if (body.empty())
    {
        ret = -1;
        fprintf(stderr, "%s invalid parameter\n", func);
        return ret;
    }

    do 
    {
        // 2. 解析json
        pstRoot = cJSON_Parse(body.c_str());
        if (NULL == pstRoot)
        {
            fprintf(stderr, "%s parse response json error .\n", func);
            break;
        }

        // 3.提取accessToken
        pstNode = cJSON_GetObjectItem(pstRoot, "accessToken");
        if (NULL == pstNode || cJSON_String != pstNode->type)
        {
            fprintf(stderr, "%s invalid data type\n", func);
            break;
        }

        accessToken = pstNode->valuestring;

    } while (0);

    // 释放资源
    if (pstRoot)
    {
        cJSON_Delete(pstRoot);
        pstRoot = NULL;
    }

    return ret;

}

 

标签:std,segmentation,string,accessToken,ret,str,崩溃
From: https://www.cnblogs.com/zhanggaofeng/p/17294066.html

相关文章

  • ios::sync_with_stdio(false);
    在阅读学习别人的代码的过程中,我们有时会发现这么一行:std::ios::sync_with_stdio(false);这是由于cin比scanf要慢很多,在需要大量读入时,用此行代码可以使cin更快。为什么cin比scanf更慢呢?标准C++流与标准C流在每次输入/输出操作后同步,同步的C++流为无缓冲,而每次C++流上......
  • WPF的控件字符串内容使用StringFormat进行字符串转换
    在WPF中TextBlock的Text有时内容只需要改变个别数字,而不需要所以内容都修改,这时候就要使用StringFormat, 如:<TextBlockText="Ihavexxxfriends"/>这里面的xxx是个变量,那在Binding时应该怎样写呢<TextBlockText="{BindingFirendNumber,StringFormat='Ihave{0}firends......
  • c++ string类的字符在内存的储存位置
    1.数据<=16字节,在当前栈区#include<iostream>#include<stdio.h>#include<stdlib.h>usingnamespacestd;intmain(){stringtemp="123456789012345";//注意长度int*a=(int*)malloc(sizeof(int));intb=0;for(a......
  • c++ std::string_view
    std::string_view系C++17标准发布后新增的内容。C++17中我们可以使用std::string_view来获取一个字符串的视图,字符串视图并不真正的创建或者拷贝字符串,而只是拥有一个字符串的查看功能。std::string_view比std::string的性能要高很多,因为每个std::string都独自拥有一份字符串的拷......
  • java -- Stringbuild、Date和Calendar类
    Stringbuild类由于String类的对象内容不可改变,每次拼接都会构建一个新的String对象,既耗时,又浪费内存空间这时需要通过java提供的StringBuild类解决这个问题StringBuilder又称为可变字符序列,它是一个类似于String的字符串缓冲区,可以看作是一个容器,容器中可以装很多字符串可......
  • c++ std::variant
    std::variant是c++17引入的一个类型,其作用类似于C语言中的Union,但是比Union的功能强大的多。C语言中一个联合体Union可以储存多种类型数据,但缺点有很多。比如:1没有可用的方法来判断Union中真实储存的类型,获取值时也是内存拷贝的结果,可能会存在问题。这就只能靠程序员人脑保证......
  • [LeetCode] 2405. Optimal Partition of String
    Givenastring s,partitionthestringintooneormore substrings suchthatthecharactersineachsubstringare unique.Thatis,noletterappearsinasinglesubstringmorethan once.Return the minimum numberofsubstringsinsuchapartition.Not......
  • java学习日记20230406-StringBuilder,StringBuffer,String比较
    StringBuffer,StringBuilder,String比较: StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法相同;String:不可变字符序列,效率低,但是复用率高;StringBuffer:可变字符序列,效率较高,线程安全;StringBuider:可变字符序列,效率极高,线程不安全  String使用注意说明: ......
  • java学习日记20230406-StringBuilder类
    StringBuilder类一个可变的字符序列,此类提供一个与StringBuffer兼容的Api,但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类,因为在大多数实现中,他比StringBuffer要快----StringBuilder不是线程安全的在S......
  • java学习日记20230405-StringBuffer类
    StringBuffer类java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删很多方法与String相同,但StringBuffer是可变长度的StringBuffer是一个容器StringBuffer是final类实现了Serializable接口,可以保存到文件或网络传输继承了抽象类AbstractStringBuiderAbstra......