Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Освобождение памяти - Динамический массив из записей / 17 сообщений из 17, страница 1 из 1
07.06.2019, 16:13
    #39824148
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
Есть динамический массив записей
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
type
TSubjectItem = record
  Name: string;
  Value: string;
end;
TSubjectArray = array of TSubjectItem;
...
FItems: TSubjectArray;


Во время работы добавляю в него элементы:
Код: pascal
1.
2.
3.
4.
procedure TSubject.Add(Item: TSubjectItem);
begin
  FItems := FItems + [Item];
end;


При выходе, освобождаю выделенную под нее память память :
Код: pascal
1.
SetLength(FItems, 0);


Так вот, иногда на этом SetLength вываливается ошибка "Invalid pointer operation"
В чем проблема? Записи нужно как-то специально зачищать?
...
Рейтинг: 0 / 0
07.06.2019, 16:37
    #39824173
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-TalkerПри выходе, освобождаю выделенную под нее память память :
Код: pascal
1.
SetLength(FItems, 0);

Это не обязательно. Он сам убьется как только выйдет из зоны видимости


SQL-TalkerТак вот, иногда на этом SetLength вываливается ошибка "Invalid pointer operation"
В чем проблема?Где-то портится память.

Подключайте FastMM в FullDebugMode и смотрите
...
Рейтинг: 0 / 0
07.06.2019, 17:20
    #39824195
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
_Vasilisk_,

Подключил. Получил сообщение об утечке
Проблемы в этой процедуре:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
function Cert_GetSubjectStr(aCertContext: PCCERT_CONTEXT): string;
type
  CERT_RDN_ARRAY = array of CERT_RDN;
var
  i: Integer;
  pvStructInfo: PVOID;
  cbStructInfo: DWORD;
  pCertNameInfo: PCERT_NAME_INFO;
  vRDNAttr: PCERT_RDN_ATTR;
  pszValue: PWIdeChar;
  RDNValueSize: DWORD;
  pInfo: PCCRYPT_OID_INFO;
  szName, szValue: string;
begin
  // декодируем Subject
  if CryptDecodeObject(
    X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
    X509_UNICODE_NAME, //X509_NAME,
    aCertContext.pCertInfo.Subject.pbData,
    aCertContext.pCertInfo.Subject.cbData,
    CRYPT_DECODE_NOCOPY_FLAG,
    nil,
    cbStructInfo
  )
  then
  begin
    GetMem(pvStructInfo, cbStructInfo);
    try
      CryptDecodeObject(
        X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
        X509_UNICODE_NAME, //X509_NAME,
        aCertContext.pCertInfo.Subject.pbData,
        aCertContext.pCertInfo.Subject.cbData,
        CRYPT_DECODE_NOCOPY_FLAG,
        pvStructInfo,
        cbStructInfo
      );

      pCertNameInfo := PCERT_NAME_INFO(pvStructInfo);

      // перебираем массив атрибутов Subject-а
      for i := 0 to (pCertNameInfo.cRDN - 1) do
      begin
        vRDNAttr := CERT_RDN_ARRAY(pCertNameInfo.rgRDN)[i].rgRDNAttr;
        CertRDNValueToStr(vRDNAttr.dwValueType, @vRDNAttr.Value, nil, RDNValueSize);
        if RDNValueSize > 0 then
        begin
          GetMem(pszValue, RDNValueSize);       // <<<<<----- Строка 1323
          try
            CertRDNValueToStr({vRDNAttr.dwValueType} CERT_RDN_UNICODE_STRING, @vRDNAttr.Value, pszValue, RDNValueSize);
            pInfo := CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, PChar(vRDNAttr.pszObjId), 0);
            szName := PWideChar(pInfo.pwszName);
            szValue := PWideChar(pszValue);
            Result := Result + szName + '=' + szValue + #13#10;
          finally
            FreeMem(pszValue, RDNValueSize);        // <<<<<----- Строка 1331
          end;
        end;
      end;
    finally
      FreeMem(pvStructInfo, cbStructInfo);
    end;
  end;

  Result := Trim(Result);
end;


Проблемы связаны с вызовом CertRDNValueToStr в строке 1325 - если этот вызов закомментировать, то утечки не будет...
Но что тут не так??
...
Рейтинг: 0 / 0
07.06.2019, 17:21
    #39824197
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
Скрин сообщения об утечке:
...
Рейтинг: 0 / 0
07.06.2019, 17:21
    #39824198
DmSer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
"Invalid pointer operation" - это ошибка, которую генерирует дельфёвый менеджер памяти, если ему подсовывают левый (неизвестный ему) указатель (или nil).

TSubject.Add случайно не вызывается одновременно из параллельных потоков?
...
Рейтинг: 0 / 0
07.06.2019, 17:23
    #39824199
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
DmSer,

Нет, тут все в одном потоке
...
Рейтинг: 0 / 0
07.06.2019, 17:32
    #39824204
cptngrb
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
Код: pascal
1.
FreeMem(pszValue, RDNValueSize);



замени на
Код: pascal
1.
FreeMem(pszValue); 
...
Рейтинг: 0 / 0
07.06.2019, 17:43
    #39824209
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-Talker,

В FullDebugMode он ещё и лог-файл создаёт, а если включить map-файл, то он даже строчки кода туда засунет где что происходит.
...
Рейтинг: 0 / 0
07.06.2019, 17:46
    #39824211
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
cptngrb,

ничего не изменилось
...
Рейтинг: 0 / 0
07.06.2019, 18:05
    #39824232
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-TalkerСкрин сообщения об утечке:

Это не утечка. Это Memory Corrupted - повреждение памяти. О чем я и говорил
SQL-TalkerНо что тут не так??То, что вы используете случайный размер памяти

SQL-Talker
Код: pascal
1.
 CertRDNValueToStr(vRDNAttr.dwValueType, @vRDNAttr.Value, nil, RDNValueSize);

https://docs.microsoft.com/en-us/windows/desktop/api/wincrypt/nf-wincrypt-certrdnvaluetostra psz

A pointer to a buffer to receive the returned string.

csz

Size, in characters, allocated for the returned string. The size must include the terminating NULL character.

Return Value
Returns the number of characters converted, including the terminating NULL character. If psz is NULL or csz is zero, returns the required size of the destination string.

Remarks
If psz is not NULL and csz is not zero, the returned psz is always a possibly empty null-terminated string.
SQL-Talker
Код: pascal
1.
CertRDNValueToStr(vRDNAttr.dwValueType, @vRDNAttr.Value, nil, RDNValueSize);
...
Рейтинг: 0 / 0
07.06.2019, 18:26
    #39824255
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
_Vasilisk_,

авторIf psz is NULL or csz is zero, returns the required size of the destination string.
psz я и выставляю в nil
прямо сейчас выставил RDNValueSize := 0; перед вызовом - после вызова RDNValueSize = 0 !!! черт возьми!
что не так с вызовом?
...
Рейтинг: 0 / 0
07.06.2019, 18:30
    #39824259
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-Talkerчто не так с вызовом? Return Value
Returns the number of characters converted, including the terminating NULL character. If psz is NULL or csz is zero, returns the required size of the destination string.
...
Рейтинг: 0 / 0
07.06.2019, 18:30
    #39824260
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-Talker,

Код: pascal
1.
RDNValueSize := CertRDNValueToStr({vRDNAttr.dwValueType} CERT_RDN_UNICODE_STRING, @vRDNAttr.Value, nil, 0);
...
Рейтинг: 0 / 0
07.06.2019, 18:32
    #39824263
SQL-Talker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
_Vasilisk_,

Блин, смотрю в книгу - вижу фигу.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
22.12.2020, 17:12
    #40030248
imkot
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
SQL-Talker,

Под XE8 у меня проблемы с чтением данных в PWIdeChar при помощи CertRDNValueToStr
В конце концов возникает ошибка работы с памятью.

Вот так работает:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
function GetCertSubjectAttr(Cert: PCCERT_CONTEXT): String;
var
  i: Integer;
  pvStructInfo: PVOID;
  cbStructInfo: DWORD;
  pCertNameInfo: PCERT_NAME_INFO;
  vRDNAttr: PCERT_RDN_ATTR;
  psz: array of WideChar; // Заменяем на массив
  RDNValueSize, RDNValueSizeRead: DWORD;
  pInfo: PCCRYPT_OID_INFO;
  S: string;
begin
  Result := '';
  // декодируем Subject
  if CryptDecodeObject(
    X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
    X509_UNICODE_NAME, //X509_NAME,
    Cert.pCertInfo.Subject.pbData,
    Cert.pCertInfo.Subject.cbData,
    CRYPT_DECODE_NOCOPY_FLAG,
    nil,
    cbStructInfo
  )
  then
  begin
    GetMem(pvStructInfo, cbStructInfo);
    try
      CryptDecodeObject(
        X509_ASN_ENCODING or PKCS_7_ASN_ENCODING,
        X509_UNICODE_NAME, //X509_NAME,
        Cert.pCertInfo.Subject.pbData,
        Cert.pCertInfo.Subject.cbData,
        CRYPT_DECODE_NOCOPY_FLAG,
        pvStructInfo,
        cbStructInfo
      );

      pCertNameInfo := PCERT_NAME_INFO(pvStructInfo);

      // перебираем массив атрибутов Subject-а
      for i := 0 to (pCertNameInfo.cRDN-1) do
      begin
        vRDNAttr := CERT_RDN_ARRAY(pCertNameInfo.rgRDN)[i].rgRDNAttr;
//        RDNValueSize := CertRDNValueToStr(vRDNAttr.dwValueType, @vRDNAttr.Value, nil, 0);
        RDNValueSize := CertRDNValueToStr(CERT_RDN_UNICODE_STRING, @vRDNAttr.Value, nil, 0);
        if RDNValueSize > 0 then
        begin
          SetLength(psz, RDNValueSize); // Выделяем память таким образом, потому что при использовании GetMem|FreeMem в конце концов ловим ошибку.
          try
            RDNValueSizeRead := CertRDNValueToStr(CERT_RDN_UNICODE_STRING, @vRDNAttr.Value, @psz[0], RDNValueSize);
            pInfo := CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, PChar(vRDNAttr.pszObjId), 0);
            if Result <> '' then
              Result := Result + sLineBreak;
            if Assigned(pInfo) then
            begin
              S := WideCharToString(pInfo.pwszName);
              Result := Result + S + '=';
            end;
            S := WideCharLenToString(@psz[0], RDNValueSizeRead);
            Result := Result + S;
          finally
            pInfo := nil;
            SetLength(psz, 0);
          end;
        end;
      end;
    finally
      FreeMem(pvStructInfo, cbStructInfo);
    end;
  end;
end;
...
Рейтинг: 0 / 0
22.12.2020, 17:22
    #40030253
Gerasimenko
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
imkot,

замени на TObjectList
...
Рейтинг: 0 / 0
22.12.2020, 18:02
    #40030280
imkot
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Освобождение памяти - Динамический массив из записей
Gerasimenko,

да я баран, надо же так делать

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
var
 psz: PWideChar;
 RDNValueSize: DWORD;
begin
  RDNValueSize := n; 
  GetMem(psz, RDNValueSize * SizeOf(WideChar));
  FreeMem(psz);
end
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Освобождение памяти - Динамический массив из записей / 17 сообщений из 17, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]