Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с функциями SysAllocString/SysFreeString 
V
    Опции темы
ParaPik
Дата 30.9.2011, 22:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



У меня имеются 2 переменные типа BSTR. Инициализирую их следующим образом:
Код

BSTR first = SysAllocString(_T(""));
BSTR second = SysAllocString(_T(""));


Потом вторая переменная в цикле изменяется так:
Код

SysFreeString(second);
SysAllocString(some_value);
 

Проблема в том, что спустя буквально 2-3 итераций цикла адрес, хранящийся в second, становится равный значению переменной first. Т.е. теперь они указывают на одну и ту же строку, first хранит some_value и second хранит some_value!!!
Пожалуйста, помогите разобраться.
PM MAIL   Вверх
Estranged
Дата 1.10.2011, 11:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



Да ладно, чудес не бывает. Код цикла приложите.
PM MAIL   Вверх
ParaPik
Дата 1.10.2011, 13:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



Так, в том то и дело, что это и есть код цикла. Но если в более подробном варианте:
Код

while (isListening)
{
       wstring str;
       //Дальше идет работа с переменной str
       SysFreeString(second);
       second = SysAllocString(str.c_str());
}


Т.е. изменение переменной second происходит только в конце цикла. Нигде она больше не изменяется. 
PM MAIL   Вверх
Estranged
Дата 1.10.2011, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



Просто, как копейка. Как вариант, может быть переполнение буфера где-то или чтение за границей буфера. Приложите весь код функции. Да не может такого быть, чтобы first совпал с новым SysAllocString. Потому что это слишком не правдоподобно.
PM MAIL   Вверх
ParaPik
Дата 1.10.2011, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



Я тоже удивился. Функцию полностью показывать нет смысла. В приложении один поток. Проверял работу кода отладчиком. Именно после очередного вызова SysAllocString происходит приравнивание адресов.
Код

second = SysAllocString(str); //После этой строки отладчик показывает, что адрес second равен адресу first.

PM MAIL   Вверх
mes
Дата 1.10.2011, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(ParaPik @  1.10.2011,  21:29 Найти цитируемый пост)
Функцию полностью показывать нет смысла.

да и вопрос на форуме задавать смысла нет, тут телепатов нет.. 



--------------------
PM MAIL WWW   Вверх
ParaPik
Дата 2.10.2011, 10:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



Вот:
Код

BSTR Func()
{
    int16 adbuf[4096];
    int32 k, ts, rem;    
    int32 score = 0;
    const char ** uttid = nullptr;

        if (m_result != nullptr)
               SysFreeString(m_result);

    if (ad_start_rec(m_rec_config) < 0)

    {
        START_PERROR("Failed to recording!")
        END_PERROR
    }



    while ((k = cont_ad_read(m_cont_ad, adbuf, 4096)) == 0)
        Sleep(100);

    if (k < 0)        
    {
        ad_stop_rec(m_rec_config);

        START_PERROR("Failed to read audio!")
        END_PERROR

    }

    if (ps_start_utt(m_ps, NULL) < 0)    
    {
        ad_stop_rec(m_rec_config);
        START_PERROR("Failed to start utterance!");
        END_PERROR

    }

    ps_process_raw(m_ps, adbuf, k, FALSE, FALSE);       
    
    ts = m_cont_ad->read_ts;

    for (;;) {
        
        if ((k = cont_ad_read(m_cont_ad, adbuf, 4096)) < 0)    
        {
            ad_stop_rec(m_rec_config);

            START_PERROR("Failed to read audio!");
            END_PERROR
        }

        if (k == 0) {            
            
            if ((m_cont_ad->read_ts - ts) > m_def_sil_len)
                break;
        }
        else {            
            ts = m_cont_ad->read_ts;
        }

        
        rem = ps_process_raw(m_ps, adbuf, k, FALSE, FALSE);
        
        if ((rem == 0) && (k == 0))
            Sleep(20);
    }
    
    ad_stop_rec(m_rec_config);
    while (ad_read(m_rec_config, adbuf, 4096) >= 0);

    cont_ad_reset(m_cont_ad);

    ps_end_utt(m_ps);    


    wstring t_result;
        
    GetUnicodeString(ps_get_hyp(m_ps, &score, uttid), &t_result);
    
    if (!m_isLM)
    {    
        for (ps_nbest_t * hyps = ps_nbest(m_ps, 0, -1, nullptr, nullptr); hyps != nullptr; hyps = ps_nbest_next(hyps))
        {        
            const char * _hyp = ps_nbest_hyp(hyps, &score);

            if (_hyp != nullptr)
            {
                if (strlen(_hyp) != 0)
                {                
                    wstring tmp;
                    GetUnicodeString(_hyp, &tmp);

                    if (t_result.find(tmp.c_str()) == wstring::npos)
                    {
                        t_result.append(1, _T('{'));
                        t_result.append(tmp.begin(), tmp.end());
                        t_result.append(1, _T('}'));
                    }
                }
            }
        }
    }
    
    m_result = SysAllocString(t_result.c_str()); //Вот здесь ошибка
    return m_result;
}


Это сообщение отредактировал(а) ParaPik - 2.10.2011, 10:10
PM MAIL   Вверх
Estranged
Дата 2.10.2011, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



А где здесь first?

Я бы заменил
Код

if (strlen(_hyp) != 0)


на
Код

if (_hyp [0] != '\0')


Зачем грызть всю строку...

Зачем тут _T? Ведь wstring t_result.
Код

 t_result.append(1, _T('{'));


PM MAIL   Вверх
ParaPik
Дата 2.10.2011, 14:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



Цитата(Estranged @ 2.10.2011,  11:59)
А где здесь first?

Я бы заменил
Код

if (strlen(_hyp) != 0)


на
Код

if (_hyp [0] != '\0')


Зачем грызть всю строку...

Зачем тут _T? Ведь wstring t_result.
Код

 t_result.append(1, _T('{'));

По поводу _T. Я просто убрал из примера препроцессорные директивы, в которых проверяется _UNICODE.
По поводу strlen согласен. Что-то я поспешил...
Простите, что забыл описать макрос START_PERROR. Он вызывает следующую функцию:
Код

void SetError(const WCHAR * str)
{
        if (m_error != nullptr)
              SysFreeString(m_error);
        m_error = SysAllocString(str);
}


m_error - это и есть first.
Я уже пробовал оберткой _bstr_t воспользоваться. Думал, мало ли я что-то не так делаю. Результата ноль.
PM MAIL   Вверх
Estranged
Дата 2.10.2011, 21:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



Цитата(ParaPik @  30.9.2011,  22:10 Найти цитируемый пост)
Проблема в том, что спустя буквально 2-3 итераций цикла адрес, хранящийся в second, становится равный значению переменной first. Т.е. теперь они указывают на одну и ту же строку, first хранит some_value и second хранит some_value!!!


Т.е. в цикле вызывается функция Func? 
m_error инициализировано в "".
А что хранится в m_error в тот момент, когда проходит ошибка (m_result = SysAllocString(t_result.c_str()); //Вот здесь ошибка) и что за строка должна быть, т.е. чему равен t_result. Правильно ли я понимаю, что SysAllocString принимает одну строку t_result, а выдает что-то постороннее, или все же возвращает нужное, но и в этот же момент m_error тоже изменяется на это some_value? Т.е. опишите подробнее состояние всех переменных до ошибки и в момент после вызова SysAllocString, когда уже все плохо.
PM MAIL   Вверх
ParaPik
Дата 2.10.2011, 23:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



Да, в цикле вызывается Func. При первом вызове функции m_error указывает на "". После первой итерации m_result принимает правильное значение, m_error свое значение не изменяет. То же самое и  во второй итерации. Но на третьей итерации SysAllocString возвращает адрес, который содержится в m_error. Этот адрес присваевается m_result. Т.е. теперь обе переменные указывают на одну и ту же строку, строку, верную для m_result. То же самое происходит, даже если m_error указывает на строку не нулевой длины.
PM MAIL   Вверх
Estranged
Дата 3.10.2011, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



А на третьей итерации в SysAllocString что подается, чему равно t_result? Какая строка? И как я понял, m_error на третьей итерации все еще не меняет свое значение, т.е. равен "". Иными словами должно получаться, что в m_result теперь тоже лежит "" и это верно. Так? Т.е. и m_result, и m_error равны "". Я правильно понимаю?
PM MAIL   Вверх
ParaPik
Дата 3.10.2011, 13:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



t_result практически всегда не нулевая строка. И на третьей итерации она тоже не нулевая. Значение m_error не меняется, а SysAllocString на третьей итерации возвращает значение, содержащиеся в m_error, т.е. ячейка памяти, на которую указывает m_error перезаписывается на содержимое t_result.
Еще я заметил, что такое происходит только тогда, когда при первой инициализации m_result SysAllocString передать пустую строку. Я не знаю, может, это проявилось бы при больших итерациях  и при начальной инициализации m_result не пустой строкой. Но самый явный баг в первом случае.
PM MAIL   Вверх
Estranged
Дата 3.10.2011, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



Теперь понятно. Такая багофича есть. А для m_error SysFreeString не вызывается где-нибудь скрыто и незаметно без парного SysAllocString до вызова m_result = SysAllocString(t_result.c_str())? Потому что после SysFreeString строка не уничтожается, а висит в памяти до ближайшего вызова SysAllocString, отчего два указателя указывают на одну память, но уже с другими данными, и один из указателей невалидный.

Убедитесь сами:
Код

    BSTR bs, bs2;

    bs = SysAllocString (L"1");// вполне хорошая строка

    SysFreeString (bs); // удалили, но по адресу по-прежнему лежит 1
    bs2 = SysAllocString (L"2"); // а вот тут уже по тому же самому адресу мы запишем 2, отчего bs уже как бы ссылается на строку 2


Если SysFreeString снести вниз за второй SysAllocString, то и bs, и bs2 хранят свои строки. Отчего я думаю, у Вас есть SysFreeString для m_error без пары SysAllocString, отчего система думает, что строка некогда лежавшая в m_error свободна, отчего использует этот регион памяти повторно, и как бы кажется, что m_error как бы принимает значение t_result, хотя в действительности m_error хранит уже некорректный адрес.

Вот как-то так...
PM MAIL   Вверх
ParaPik
Дата 3.10.2011, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 132
Регистрация: 8.1.2009

Репутация: нет
Всего: нет



SysAllocString и SysFreeString вызывались только парами. Скрыто ничто не может изменить значение. Я уже все заменил на _bstr_t. С этой оберткой вопрос о неправильном освобождении памяти точно отпадает(ничего из-за этого не изменилось). Но я все-таки решил эту проблему. Я теперь просто инициализирую m_error не "", а nullptr. Все равно мне нужно будет получить лишь одну строку: либо m_error, либо m_result. Больше я не вижу решений.
В любом случае, спасибо, Estranged, за участие в решении моей проблемы.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.1373 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.