C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Acces Violation Error
Danka
Отправлено: 05.02.2004, 17:00


Не зарегистрирован







Привет. Я создала трёхуровневая программу. SQL_Server---Midas Server----ActiveX Client-Form. Я создаю весьма длиные и сложные SQL запросы (много join, group by, etc.). Запросы правильные, они выполняются, хотя долго. Но после выполнения запросов в IE Browser-e начинаються ошибки типа Acces Violation at "0x0...", Memory could not be read, etc. Ошибки не связаны ни с каким Event-ом. Иногда сразу появляются, иногда позже. От чего такие ошибки? От указателей? Вроде проверила. От чего ещё?
Спасибо.
Ламер (редкий)
Отправлено: 05.02.2004, 18:15


Не зарегистрирован







проверьте вашу прогу на наличие функций
strcpy, strcat strncpy и других
так как эти заразы не контролируют длину строк-аргументов,
за нефиг можно переполнить стек, если длина строки слишком велика
Doga
Отправлено: 05.02.2004, 19:13


Мастер участка

Группа: Участник
Сообщений: 575



Подключи к проекту библиотеку CodeGuard (Project->Options->CodeGurd), откомпилируй (Full Debug) и запусти...
Danka
Отправлено: 06.02.2004, 10:57


Не зарегистрирован







Я подключила к проекту библиотеку CodeGuard. В log-file вывелись ошибки типа :
у ActiveX Client-a:
Error 00001. 0x300010 (Thread 0x0D58):
Resource leak: The memory block (0x3C5A4CC) was never freed

The memory block (0x03C5A4CC) [size: 22 bytes] was allocated with SysGetMem
Call Tree:
0x036C9DDF
0x036AD32D
..............

y Midas Server-a:
Error 00001. 0x300010 (Thread 0x0D78):
Resource leak: The object (0xE49ED8) was never deleted

The object (0x00E49ED8) [size: 12 bytes] was created with new
Call Tree:
0x0040F38F(=PR_TRA~1.EXE:0x01:00E38F) c:\program files\borland\cbuilder6\include\atl\atlbase.h#5824
0x0040EA03(=PR_TRA~1.EXE:0x01:00DA03) c:\program files\borland\cbuilder6\include\atl\atlbase.h#2647
0x0040DBD4(=PR_TRA~1.EXE:0x01:00CBD4) c:\program files\borland\cbuilder6\include\atl\atlcom.h#3471
...........
и
Error 00002. 0x300010 (Thread 0x0D78):
Resource leak: The object array (0xE49D98) was never deleted

The object array (0x00E49D98) [size: 316 bytes] was created with new[]
Call Tree:
0x0040E70F(=PR_TRA~1.EXE:0x01:00D70F) c:\program files\borland\cbuilder6\include\atl\atlcom.h#3410
.............

У клиента я использую strtok в примерно таком коде:
AnsiString trunk_a;
if(CheckBoxTrunk_A->Checked)
trunk_a=strtok(ComboBoxTrunk_A->Text.c_str()," ");


AnsiString TSelectCpt::get_User()
{
LPTSTR lpszSystemInfo;
DWORD cchBuff = 1024;
TCHAR tchBuffer[1024];
lpszSystemInfo = tchBuffer;
//AnsiString userName;
if( GetUserName(lpszSystemInfo, &cchBuff) )
user=lpszSystemInfo;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(1, 0);
int err = WSAStartup(wVersionRequested, &wsaData);
//AnsiString domen, comp;
if(err == 0)
{
char hn[1024];
struct hostent *adr;
if(gethostname((char *)&hn, 1024))
{
WSAGetLastError();
Beep();
}
adr = gethostbyname(hn);
if(adr)
{
comp=strtok(adr->h_name,".");
domen=strtok(NULL,".");
}
}
return user+"_"+comp+"."+domen+"_";
}

У клиента я создаю array из ТQRDBText

TQRDBText* TabTempText[3]={QRDBText1,QRDBText2,QRDBText3};

for(int i=0;i<3;i++)
{
TabQRText[i]=TabTempText[i];
TabQRText[i]->DataField="";
}
где
private: // User declarations
TQRDBText* TabQRText[3];


У сервера есть и array, и strtok в коде:
AnsiString c="1 16 17";//не больше 20 символов
AnsiString t[10];
int n=0;
if(AnsiCompareStr(c,"")!=0)
{
char *p;
p=strtok(c.c_str()," ");
do
{
t[n]=p;
p=strtok(NULL," ");
n++;
} while(p);
}

В переменых типа AnsiString я всатавляю очень большие строки. Это может вызвать ошибку?
Doga
Отправлено: 06.02.2004, 17:29


Мастер участка

Группа: Участник
Сообщений: 575



По сообщениям CodeGuard ты не освобождаешь выделенную некоторым переменным память — это плохо. Имена этих переменных придется искать в отладчике по их адресам.

Если для переменной выделена память оператором new[] — она должна быть освобождена оператором delete[].
Типа:

char *CC = new char[1000];
delete[] CC;

Проверь очистку памяти в деструкторах своих классов, которая была выделена при их инициализации или в ходе их работы.


Этот код доволно опасен:

char *p;
p=strtok(c.c_str()," ");
do
{
t[n]=p;
p=strtok(NULL," ");
n++;
} while(p);

c_str() возвращает указатель на локалный буфер класса AnsiString, который может быть изменён в любой момент(напр в другой процедуре, твоим клиентом иль сервером)
и тогда етот указатель уже будет не рабочий. Лучше сделать так:

char ссс[c.Legth() + 1];
StrLCopy(ccc, c.c_str(), c.Legth());

char *p;
p=strtok(ccc," ");
do
{
t[n]=p;
p=strtok(NULL," ");
n++;
} while(p);

Так лучше переделать для всех вызовов strtok.



Длина строки класса AnsiString может иметь неограниченню длину и занимать всю доступную память.

А пследствия работы программы дествительно похожи на выход за границы массива. Попробуй использовать только AnsiString и откажись от *char там где это возможно. А где невозможно — делай проверку на выход за границы массива.
Guest
Отправлено: 06.02.2004, 18:00


Не зарегистрирован







Я не выделяю память оператором new[] ни для одной переменной, так что ошиба наверно не в этом. Указатели я только в том коде использую, в остальных случаях AnsiString.
Что меня беспокоит это то что я сделала новый ActiveX(чистый, один только TLabel) и он тоже даёт ошибки в CodeGuard-e и на моём компе, и на другом. ActiveX-ы выполняются на компе клента. В чем тогда ошибка?
Danka
Отправлено: 06.02.2004, 18:11


Не зарегистрирован







biggrin.gif ой, я имя забыла написать в предыдущем сообщении
Doga
Отправлено: 09.02.2004, 14:22


Мастер участка

Группа: Участник
Сообщений: 575



Так я не понял, ты ошибки , о которых сообщал CodeGuard, исправила?Он же собщил тебе адреса переменных!

Дальше. Если это не поможет включи в проэкте вывод ВСЕХ варнингов (по умолчанию не все выводятся) и внимательно изучи их — варнинги тож иногда мешают проге.

" Я не выделяю память оператором new[] ни для одной переменной" — я не представляю себе прогу без оператора new biggrin.gif

А вообще не имея исходного кода, заочно, вряд ли чем можно помочь.
Придётся тебе самой, наверное сидеть в отладчике и выяснять что в проге происходит с твоими подозрительными переменными.

А почему ты решила, что именно те переменные подозрительные? Может ты ищешь не там, где потеряла а там, где светлей ? smile.gif
Danka
Отправлено: 10.02.2004, 09:15


Не зарегистрирован







Нет, я не исправила ошибки , о которых сообщал CodeGuard потому что я не знаю как это сделать, как найти переменную по её физическому адресу. sad.gif Подскажи пожалуйста.
Doga
Отправлено: 11.02.2004, 15:08


Мастер участка

Группа: Участник
Сообщений: 575



Оч просто. Перед компиляцией проэкта убедись что она пройдет в режиме полной отладки (Full Debug). Далее в тексте проги ставишь точку остановки напротив нужной тебе переменной и запускаешь проэкт в отладчике — программа в этом месте будет остановлена.
После чего наводишь курсор наеё имя и видишь хинт, типа: ABC = :011A5004 . 011A5004 — и есть адрес переменной ABC(в шестнадцатиричном виде). Осталось ток сравнить адрес этой переменной с тем адресом на который указывает CodeGuard. И если они вдруг совпадут, считай что ты сделаа это! smile.gif
Вообще то CodeGuard будет выдавать свои сообщения с адресами когда ты уже не сможешь узнать адрес переменной, напр перед закрытием проги иль в конце работы функции, так что запиши себе адрес переменной в процессе её инициализации, а сравнивать будешь ток когда CodeGuard выдаст адрес.
Если ABC класс, то можно получить болле подробную информацию о его текущем состояниии в инспекторе отладки (Debug Inspector): щелкни на имени правой кнопкой мыши — появится всплывающая менюшка(вообще Debug Inspector работает с переменными всех типов). Выбери в ней пункт Debug  — появится ещё одна менюшка и далее в ней выбери пункт Inspect... — тут то ты и увидишь тот самый инспектор отладки. Открывай закладку Properties и смотри. Если вместо значения свойства строка вроде: (read=... write=...)  — щелкни на ней, а затем на появившийся "?" — увидишь текущее значение свойства.

А на будующее когда будешь писать очередную прогу советую поступать следующим образом: как только выделяешь память для Чего Либо, сразу напиши код для освобождения памяти от етого Либо Чаго! И ток потом пиши то что ты с етим Чаго Либо хочешь сделать. Проблем будет гораздо меньше! biggrin.gif

Да! И незабуди перед очисткой памяти от Чаго Либо проверить есть ли оно вообще. А то бывают такие казусы, когда уже очищенную память очищаешь ещё и ещё раз! Последствя не предсказуемы! biggrin.gif

И ещё.

УДАЧИ!!!

smile.gif

Вернуться в Вопросы программирования в C++Builder