Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 22.01.2013, 14:36   #1
Антон Ю.Б.
Форумчанин
 
Регистрация: 03.01.2009
Сообщений: 116
По умолчанию Выделение малых фрагментов памяти в dll

Коллеги. Не подскажет ли кто - в какую сторону можно посмотреть. Есть вот такой код (delphi XE) работы с AT-модемом.

Код:
var TempS:string;

procedure GetModemResponse(var Res: PString; var ResLen: Integer);
begin
  TempS:=ModemWork.GetModemResponse;
  TempS:=Trim(TempS);
  ResLen:=Length(TempS);
  if ResLen>0
  then
    begin
      GetMem(Res, ResLen*2);
      try
        Res^:=TempS;
      except on E: Exception do
        begin
          AppendToLog('Error on get string "'+TempS+'" '+IntToStr(Reslen)+' '+IntTostr(Integer(@TempS[1]))+' '+E.Message);
          FreeMem(Res, ResLen*2);
          ResLen:=0;
        end;
      end;
    end;
end;

procedure LibFreeMem(var Res: PString; ResLen: Integer);
begin
  if ResLen>0
  then FreeMem(Res, ResLen*2);
end;
Вполне себе работает, кроме случаев, когда ответы модема короткие - символов до 6.В этом случае в логе:
Код:
14:29:35: Error on get string "OK" 2 141533220 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:36: Error on get string "OK" 2 141533268 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:37: Error on get string "OK" 2 141533292 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:38: Error on get string "OK" 2 141533316 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:39: Error on get string "OK" 2 141533340 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:40: Error on get string "OK" 2 141533364 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:42: Error on get string "OK" 2 141533388 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:43: Error on get string "OK" 2 141533412 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:44: Error on get string "OK" 2 141533436 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:45: Error on get string "OK" 2 141533460 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:46: Error on get string "OK" 2 141533484 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
14:29:47: Error on get string "OK" 2 141533508 Access violation at address 07C59E98 in module 'ATModem.dll'. Read of address 432B5439
Может какие-то свойства проекта выставить надо, директивы компилятора?
Антон Ю.Б. вне форума Ответить с цитированием
Старый 22.01.2013, 14:46   #2
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,442
По умолчанию

Ошибка здесь:
Код:
     GetMem(Res, ResLen*2);
Для UNICODE да и вообще, надо так: Length('строка') * SizeOf(Char)

И для FreeMem не надо явно указывать размер высвобождаемой памяти, он сам это делает.
Человек_Борща вне форума Ответить с цитированием
Старый 22.01.2013, 15:06   #3
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Это лихо вы PString пользуете, думаете не String и в DLL проканает?
TempS - тип какой? string?
если да то что для вас такое string? указатель на массив символов? - нет нет и нет... это указатель на структуру типа StrRec для удобства значение смещено на SizeOf(StrRec) чтоб сразу полезные данные шли
в 7дельфе строка это
StrRec = packed record
refCnt: Longint;
length: Longint;
end;
в вашей реализации псевдо строки этого нет что при выполнении Res^:=TempS; все ломает
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 22.01.2013 в 15:10.
Slym вне форума Ответить с цитированием
Старый 22.01.2013, 15:10   #4
Антон Ю.Б.
Форумчанин
 
Регистрация: 03.01.2009
Сообщений: 116
По умолчанию

Цитата:
Сообщение от Человек_Борща Посмотреть сообщение
Для UNICODE да и вообще, надо так: Length('строка') * SizeOf(Char)
Не помогает такой вариант. Все по прежнему.
Антон Ю.Б. вне форума Ответить с цитированием
Старый 22.01.2013, 15:19   #5
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Код:
function GetModemResponse(var Buffer; BufferSize: DWORD): DWORD;
var TempS:string;
begin
  TempS:=ModemWork.GetModemResponse;
  TempS:=Trim(TempS);
  if BufferSize=0 then
    result:=Length(TempS)
  else
    StrPLCopy(@Buffer,TempS,BufferSize);
end;

использование

Код:
var s:string;
begin
SetLength(s,GetModemResponse(nil,0));
SetLength(s,GetModemResponse(s[0],Length(s)));
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 22.01.2013, 15:24   #6
Человек_Борща
Старожил
 
Аватар для Человек_Борща
 
Регистрация: 30.12.2009
Сообщений: 11,442
По умолчанию

а ещё выкинуть STRING из проекты и использовать PChar или WideString или же использовать STRING и таскать с собой SHAREMEM
Человек_Борща вне форума Ответить с цитированием
Старый 22.01.2013, 16:03   #7
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,792
По умолчанию

Цитата:
а ещё выкинуть STRING
Как вариант попробовать TStringStream
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 22.01.2013, 19:24   #8
Антон Ю.Б.
Форумчанин
 
Регистрация: 03.01.2009
Сообщений: 116
По умолчанию

Slym, у меня тогда несколько уточняющих вопросов и замечаний:
1) Где указан запрет на работу со строчными ссылочными типами таким образом? p:=^.. (ну хранится указанная Вами структура с отрицательным смещением от адреса переменной и данных, ну разная эта структура для юникода и анси. И что? Язык и логика работы с указателями вроде в этом смысле остаются прежними).
2) Эта проблема была и в доюникодовом d2007 (первоначально библиотека писалась под ним).
3) Проблема есть только для строк размером 2-6 (примерно) символов, она ни одного раза не проявилась на строках большей длины, а длина там бывает на порядок-два больше.

Последний раз редактировалось Антон Ю.Б.; 22.01.2013 в 19:52.
Антон Ю.Б. вне форума Ответить с цитированием
Старый 23.01.2013, 06:01   #9
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Цитата:
Сообщение от Антон Ю.Б. Посмотреть сообщение
Slym, у меня тогда несколько уточняющих вопросов и замечаний:
1) Где указан запрет на работу со строчными ссылочными типами таким образом? p:=^.. (ну хранится указанная Вами структура с отрицательным смещением от адреса переменной и данных, ну разная эта структура для юникода и анси. И что? Язык и логика работы с указателями вроде в этом смысле остаются прежними).
Код:
library Project1;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }
PString^:=string - не тупо копирование ссылки Pointer(PChar(x))^:=PChar(y) а вызов compiller magic LStrCat и кучу других системных процедур по работе со строками - и все эти процедуры ориентированы найти поля StrRec - которые ты не создал и даже не выделил под них память



Цитата:
Сообщение от Антон Ю.Б. Посмотреть сообщение
2) Эта проблема была и в доюникодовом d2007 (первоначально библиотека писалась под ним).
Структура перед указателем на массив символов в строке была всегда (в D1 была?), и грабля эта должна везде сработать

Цитата:
Сообщение от Антон Ю.Б. Посмотреть сообщение
3) Проблема есть только для строк размером 2-6 (примерно) символов, она ни одного раза не проявилась на строках большей длины, а длина там бывает на порядок-два больше.
работа со строкой без заголовка вызывает доступ/перезапись памяти там где должна быть структура StrRec а в той памяти может хранится чтонибудь важное как поле длинны строки
[память]
строка1строка2
операция со строка2 приведет к порче строка1, т.к. по месту должны быть поля RefCount и Length
[память]
0010007строка2

или же авто освобождение compiller magic строки строка2
вызовет FreeMem ока1 - байт (поле Length) что гораздо больше 7 байт
или не вызовет вовсе т.к. RefCount 0стр - больше 0
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 23.01.2013 в 06:03.
Slym вне форума Ответить с цитированием
Старый 23.01.2013, 06:19   #10
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

у тебя работает этот код?

Код:
procedure TForm1.Button1Click(Sender: TObject);
var S1,S2:PString;
begin
  GetMem(S1,8*SizeOf(Char));
  GetMem(S2,16*SizeOf(Char));
  S1^:='01234567';
  s2^:=S1^+'76543210';
  Caption:=S2^;
  FreeMem(S2,16*SizeOf(Char));
  FreeMem(S1,8*SizeOf(Char));
end;
как не странно стоит поменять гетмемы местами и вдруг работает
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 23.01.2013 в 06:21.
Slym вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Выделение памяти Blind Guard Общие вопросы C/C++ 22 06.06.2012 19:48
Распределение памяти. Динамическое выделение памяти с++ Tolian92 Помощь студентам 8 14.05.2012 21:44
Определить SIZEMEM у DLL(Размер dll в памяти процесса) Человек_Борща Общие вопросы Delphi 6 22.07.2011 20:54
Выделение памяти в С++ Dj-IIyIIc Общие вопросы C/C++ 4 18.10.2010 14:39
выделение памяти Артем1256 Общие вопросы C/C++ 1 13.11.2009 16:38