Повреждение памяти в System.Move из-за измененного режима 8087CW (PNG + strackBlt)

StackOverflow https://stackoverflow.com/questions/2584654

  •  24-09-2019
  •  | 
  •  

Вопрос

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

Например: я делаю простую строковое задание:

sTest := 'SET LOCK_TIMEOUT ';

Однако результат иногда становится:

sTest = 'SET LOCK'#0'TIMEOUT '

Итак, _ заменяется на байт 0.

Я видел, что это произошло однажды (воспроизводство сложно, зависит от времени) в функции System.Move, когда она использует стек FPU (FILD, FISTP) для быстрой копии памяти (в случае перемещения 9 до 32 байта):

...
@@SmallMove: {9..32 Byte Move}
fild    qword ptr [eax+ecx] {Load Last 8}
fild    qword ptr [eax] {Load First 8}
cmp     ecx, 8
jle     @@Small16
fild    qword ptr [eax+8] {Load Second 8}
cmp     ecx, 16
jle     @@Small24
fild    qword ptr [eax+16] {Load Third 8}
fistp   qword ptr [edx+16] {Save Third 8}
...

Используя вид FPU и 2 представления отладки памяти (Delphi -> View -> Debug -> CPU -> Память) Я видел, как будто это не так ... Однажды ... Не удалось воспроизвести ...

Этим утром я читал что-то о режиме 8087CW, и да, если это изменено на $ 27fi Получить повреждение памяти! Обычно это $ 133F:

Разница между 133F и 027F $ 133F и $ 027F заключается в том, что $ 027F устанавливает ФПУ для выполнения менее точных расчетов (ограничивающие для двойного вместо расширенных) и разных обработчиков Infiniti (который использовался для более старого FPU, но больше не используется).

Хорошо, теперь я нашел Зачем но нет когда!

Я изменил работу моего ASMPROFILER С простым чеком (так что все функции проверяются в Enter и оставьте):

if Get8087CW = $27F then    //normally $1372?
  if MainThreadID = GetCurrentThreadId then  //only check mainthread
    DebugBreak;

Я «профилированных» некоторых единиц и DLL и BINGO (см. Стек):

Windows.StretchBlt(3372289943,0,0,514,345,4211154027,0,0,514,345,13369376)
pngimage.TPNGObject.DrawPartialTrans(4211154027,(0, 0, 514, 345, (0, 0), (514, 345)))
pngimage.TPNGObject.Draw($7FF62450,(0, 0, 514, 345, (0, 0), (514, 345)))
Graphics.TCanvas.StretchDraw((0, 0, 514, 345, (0, 0), (514, 345)),$7FECF3D0)
ExtCtrls.TImage.Paint
Controls.TGraphicControl.WMPaint((15, 4211154027, 0, 0))

Так что это происходит в растяжек ...

Что делать сейчас? Это вина окон или ошибка в PNG (входит в D2007)? Или система. Move функция не отказоустойчивая?

Примечание: Просто пытается воспроизвести не работает:

  Set8087CW($27F);
  sSQL := 'SET LOCK_TIMEOUT ';

Похоже, это более экзотична ... но от отладка на «Get8087CW = $ 27F» я мог бы воспроизвести его на другой строке: PPU часть 1:FPU part 1ФПУ часть 2:FPU part 2ФПУ часть 3:FPU part 3FPU финал: COURMPY!:FPU Final: corrupt!

Заметка 2: Может быть, стек FPU должен быть очищен в системе.

Это было полезно?

Решение

Я не видел эту конкретную проблему, но двигаться, безусловно, может испортить, если FPU находится в плохом состоянии. Водитель VPN Cisco может ужасно завинчать, даже если вы не делаете ничего общего.

http://brianorr.blogspot.com/2006/11/intel-pentium-d-floation-point-unit.html. сломанный

https://web.archive.org/web/20160601043520/http://www.dankohn.com/Чахивы/343.

http://blog.excastle.com/2007/08/28/delphibug-of-the-day-fpu-stack-leak/ (Комментарии Ritchie Anand)

В нашем случае мы обнаруживаем багги VPN-драйвер и поменяйте перемен на ходу и Fillchar с версиями Delphi 7, замените InttoStr с версией Pascal (INT64-версия использует FPU), и, поскольку мы используем Fastmm, мы отключаем его на заказ Размер тоже движутся процедуры, поскольку они еще более восприимчивы, чем System.Move.

Другие советы

Это может быть ошибка в вашем видеодивере, который не сохраняет управление 8087, когда он выполняет операцию растяжения.
В прошлом я видел подобное поведение при использовании некоторых драйверов принтера. Они думают, что они владеют 8087 CW и неверны ...

Обратите внимание на значение по умолчанию 8087 CW в Delphi, кажется 1372 доллара; Для более подробного объяснения ценностей CW см. эта статья: Это также объясняет ситуацию, которую Майкл Джастин описал, когда его 8087CW вошли.

- jereen.

Просто для вашей информации (в случае, если у некоторых тоже есть такая же проблема): Мы сделали обновление нашего программного обеспечения для клиента, и полный сенсорный экран заблокирован, когда наш приложение было запущено! Окна были полностью заморожены! ПК должен был быть перезапущен (выключен). Потребовалось некоторое время, чтобы выяснить причину полной заморозки.

К счастью, у нас был один (только 1!) Stacktrace AV в FastMove.largessemove. Я отключил использование SSE в FastMove, и проблема ушла.

Кстати: сенсорный экран имеет через CPU Nehemiah с чипсетом S3.

Таким образом, вы не только можете получить повреждения памяти при использовании FPU, но и полной замораживания!

Для тех, кто по-прежнему заинтересован в этом: есть еще одна возможная причина проблем:

Delphi Rio все еще корабли с разбитой версией ASM Move.

Я имел удовольствие вступить в эту ошибку сегодня, к счастью, достаточно, у меня был воспроизводимый тестовый случай. Выпуск в этом листе кода:

* ***** BEGIN LICENSE BLOCK *****
 *
 * The assembly function Move is licensed under the CodeGear license terms.
 *
 * The initial developer of the original code is Fastcode
 *
 * Portions created by the initial developer are Copyright (C) 2002-2004
 * the initial developer. All Rights Reserved.
 *
 * Contributor(s): John O'Harrow
 *
 * ***** END LICENSE BLOCK ***** *)

// ... some less interesting parts omitted ...

@@LargeMove:
        JNG     @@LargeDone {Count < 0}
        CMP     EAX, EDX
        JA      @@LargeForwardMove

        // the following overlap test is broken
        // when size>uint(destaddr), EDX underflows to $FFxxxxxx, in which case 
        // we jump to @LargeForwardMove even if a backward loop would be appropriate
        // this will effectively shred everything at EDX + size
        SUB     EDX, ECX              // when this underflows ...
        CMP     EAX, EDX              // ... we also get CF=1 here (EDX is usually < $FFxxxxxx)
        LEA     EDX, [EDX+ECX]        // (does not affect flags)
        JNA     @@LargeForwardMove    // ... CF=1 so let's jump into disaster!

        SUB     ECX, 8 {Backward Move}
        PUSH    ECX
        FILD    QWORD PTR [EAX+ECX] {Last 8}
        FILD    QWORD PTR [EAX] {First 8}
        ADD     ECX, EDX
        AND     ECX, -8 {8-Byte Align Writes}
        SUB     ECX, EDX

использованная литература

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top