Необъяснимый out_of_range в строке :: substr - PullRequest
1 голос
/ 13 февраля 2010

Я получаю действительно досадную ошибку о std :: out_of_range при вызове substr. Точная ошибка

завершить вызов после броска экземпляр 'std :: out_of_range'
что (): basic_string :: substr

Я абсолютно уверен, что длина tmp_request больше 1. Независимо от того, что я передаю в substr - 1, 2 или bodypos - он всегда выдает эту ошибку. Я использую g ++ на Unix.

Единственная интересная вещь, которую я могу включить, это то, что строка содержит несколько "\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 ]

6 голосов
/ 14 февраля 2010

Я немного изменил ваш образец, чтобы уменьшить количество используемых отступов.
Есть 5 «тестовых случаев», и ни один не вызывает никаких проблем. Не могли бы вы предоставить пример запроса для воспроизведения проблемы, с которой вы столкнулись.

РЕДАКТИРОВАТЬ: Забыл упомянуть: если этот пример, как он есть (с закомментированными битами) не выдает эту ошибку, лучше всего, если у вас есть ошибка в вашей функции StringExplode. Вы можете опубликовать его источник, чтобы получить более полезный совет.

EDIT2: В вашем StringExplode измените results[tmpKey] = tmpKey.substr(found+1); на results[tmpKey] = tmpResult[i].substr(found+1);. Измените int found на size_t found и удалите все if (found > 0), что исправит ваш таинственный out_of_range. Вы ошиблись строкой. На всякий случай вот код с исправлением:

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;
}

Это выводит, как и ожидалось:

[делать вещи]
[делать вещи]
[делать вещи]
[]
[]

1 голос
/ 14 февраля 2010

Одна довольно очевидная вещь не так с вашим кодом:

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

Вы не проверяете, что read () завершился успешно - он возвращает -1 при сбое, что приведет к всевозможным проблемам повреждения памяти, если это произойдет.

Также:

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

Вы берете размер указателя - вы хотите длину выходной строки:

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

И вам следует еще раз проверить, что запись выполнена успешно и что она записала столько байтов, сколько вы запросили, хотя это не должно напрямую вызывать ошибку substr ().

1 голос
/ 14 февраля 2010

Вы уверены, что происходит сбой на этом substr, а не на substr вызове в функциях HttpError или StringExplode? Если вы еще этого не сделали, вы должны запустить это через отладчик, чтобы вы могли точно видеть, где он выдает исключение. Кроме того, вы можете добавить:

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

строка непосредственно перед вызовом substr, и аналогичная строка сразу после этого, чтобы она выглядела так:

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";

Если это substr действительно выдает исключение, то вы будете знать, потому что программа напечатает «вызывающий substr» без соответствующего «завершенного вызова substr». Если он печатает пару сообщений отладки, или их нет вообще, то что-то еще вызывает исключение.

0 голосов
/ 13 февраля 2010

Возможно, вы решите использовать (без знака) тип std::string::size_type вместо int.

Почему вы приводите результат поиска к int здесь: int(request.find("register"))!=std::string::npos

0 голосов
/ 13 февраля 2010

Похоже, вам нужно еще после

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

в противном случае вы вызываете substr с bodypos = npos

...