代码之家  ›  专栏  ›  技术社区  ›  stan

字符串::substr中\u超出\u范围的原因不明

  •  1
  • stan  · 技术社区  · 16 年前

    我在调用substr时遇到了一个关于std::超出\u范围的非常恼人的错误。确切的错误是

    “std::超出\u范围”的实例
    what():基本字符串::substr

    我绝对确信tmp\u请求的长度大于1。无论我传递给substr-1、2或bodypos的是什么,它总是抛出那个错误。我在Unix上使用g++。

    "\r\n" ,包括一个 "\r\n\r\n" .

    在一个cpp文件中:

    std::string tmp_request, outRequest;
    
    tmp_request = SS_Twitter->readData();
    outRequest = SS_Twitter->parse(tmp_request);
    

     std::string parse(const std::string &request)
     {
      std::map<std::string,std::string> keyval;
      std::string outRequest;
      if(request[0]=='P')
      {
       if(request.find("register")!=std::string::npos)
       { //we have a register request
        size_t bodypos = request.find("username");
        if(bodypos==std::string::npos) 
        {
         HttpError(400,"Malformed HTTP POST request. Could not find key username.",request); 
        }
        else
        {
         std::string body = request.substr(bodypos);
         StringExplode(body,"&", "=",keyval);
         outRequest = "doing stuff";
        }
    
       }
    

    std::string request2("P\r\nregister\r\nusername=hello\r\n\r\n");
    
    std::string body = request2.substr(4);
    

    同样的错误。现在我知道这是完全有效和正确的代码,但它仍然抛出错误。 //已删除源链接

    5 回复  |  直到 16 年前
        1
  •  7
  •   Dmitry    16 年前

    我稍微修改了你的样品以减少压痕的使用量。

    编辑:忘了提一下:如果这个示例(带有注释掉的位)没有产生那个错误,那么您最好的选择就是您的代码中有一个bug StringExplode

    编辑2: 在你的 改变 results[tmpKey] = tmpKey.substr(found+1); results[tmpKey] = tmpResult[i].substr(found+1); . 改变 int found size_t found ,并删除所有 if (found > 0) substr -打错了线。以防万一,下面是带有修复的代码:

    void StringExplode(std::string str, std::string objseparator, std::string keyseperator,
                       std::map <std::string, std::string> &results)
    {
        size_t found;
        std::vector<std::string> tmpResult;
        found = str.find_first_of(objseparator);
        while(found != std::string::npos)
        {
            tmpResult.push_back(str.substr(0,found));
            str = str.substr(found+1);
            found = str.find_first_of(objseparator);
        }
        if(str.length() > 0)
        {
            tmpResult.push_back(str);
        }
    
        for(size_t i = 0; i < tmpResult.size(); i++)
        {
            found = tmpResult[i].find_first_of(keyseperator);
            while(found != std::string::npos)
            {
                    std::string tmpKey = tmpResult[i].substr(0, found);
                    results[tmpKey] = tmpResult[i].substr(found+1);
                    found = tmpResult[i].find_first_of(keyseperator, found + results[tmpKey].size());
            }
    
        }
    }
    

    初始测试代码:

    #include <iostream>
    #include <map>
    #include <string>
    
    std::string parse(const std::string &request)
    {
        std::map<std::string,std::string> keyval;
        std::string outRequest;
    
        if(request[0] != 'P')
            return outRequest;
    
        if(request.find("register") == std::string::npos)
            return outRequest;
    
        //we have a register request
        size_t bodypos = request.find("username");
        if(bodypos==std::string::npos)
        {
            // HttpError(400,"Malformed HTTP POST request. Could not find key username.",request);
            // you said HttpError returns, so here's a return
            return outRequest;
        }
    
        std::string body = request.substr(bodypos);
        // StringExplode(body,"&", "=",keyval);
        outRequest = "doing stuff";
    
        return outRequest;
    }
    
    int main()
    {
    
        std::string request("P\r\nregister\r\nusername=hello\r\n\r\n");
        std::cout << "[" << parse(request) << "]\n";
    
        request = "Pregisternusername=hello\r\n\r\n";
        std::cout << "[" << parse(request) << "]\n";
    
        request = "Pregisternusername=hello";
        std::cout << "[" << parse(request) << "]\n";
    
        request = "registernusername=hello";
        std::cout << "[" << parse(request) << "]\n";
    
        request = "";
        std::cout << "[" << parse(request) << "]\n";
    
        return 0;
    }
    

    可以预见,这将产生:



    [做事]
    []
    []

        2
  •  1
  •   Josh Townzen    16 年前

    substr 而不是在飞机上 在内部呼叫 HttpError StringExplode

    std::cout << "calling substr" << std::endl;
    

    打电话前马上打电话 ,然后是一条类似的线,所以它看起来像:

    std::cout << "calling substr" << std::endl;
    std::string body = request.substr(bodypos);
    std::cout << "finished calling substr" << std::endl;
    
    StringExplode(body,"&", "=",keyval);
    outRequest = "doing stuff";
    

    如果那样的话 如果是抛出异常,那么您就知道了,因为程序将打印“calling substr”,而没有匹配的“finished calling substr”。但是,如果它打印了一对调试消息,或者根本没有,那么其他东西就会抛出异常。

        3
  •  1
  •   anon anon    16 年前

    你的代码有一个很明显的错误:

    int k = read(ns, buf, sizeof(buf)-1);
    buf[k] = '\0';
    

    也:

    char * buf2 = const_cast<char *>(reply.c_str());
    write(ns,buf2,sizeof(buf2));
    

    write(ns, buf2, reply.size() );
    

    您应该再次测试写入是否成功,以及它写入的字节数是否与您请求的字节数相同,尽管这不应该直接导致substr()错误。

        4
  •  0
  •   Jeff    16 年前

    看来你以后还需要别的

    if(bodypos==std::string::npos)
    {
        HttpError(...);
    }
    

    否则调用substr时bodypos=npos

        5
  •  0
  •   Matt Curtis    16 年前

    您可以考虑使用(无符号)类型。 std::string::size_type 而不是 int .

    为什么要在这里将find的结果转换为int: int(request.find("register"))!=std::string::npos