Kaip ištaisyti klaidų korupcijos klaidas?

„Visual Studio 2008“ derinu (patentuotą) daugiapakopę C ++ programą. Matyt, atsitiktinai gaunu pranešimą „Windows sukėlė klaidą ...“ su pastaba, kad tai gali būti padaryta dėl žalos krūvos. Šios klaidos ne visada lemia paraiškos žlugimą iš karto, nors po to gali įvykti gedimas.

Didžiausia problema, susijusi su šiomis klaidomis, yra ta, kad jie atsiranda tik tada, kai žala iš tikrųjų įvyko, todėl sunku juos stebėti ir derinti, ypač daugiapakopėje programoje.

  • Kas gali sukelti šias klaidas?

  • Kaip juos derinti?

Patarimai, įrankiai, metodai, spragos ... yra sveikintini.

147

Programos tikrintojas kartu su „Windows“ derinimo įrankiais yra nuostabus diegimas. Ją galite gauti kaip „ Windows“ tvarkyklės rinkinio arba lengvesnio „Windows SDK“ dalį . (Sužinojote apie „Application Verifier“, tiriant ankstesnį klausimą apie korupcijos krūvų problemą ). Be to, aš naudoju BoundsChecker ir Insure ++ (paminėti kituose atsakymuose), nors buvau nustebęs, kiek funkcijų buvo taikomojoje programoje.

Verta paminėti elektrinę tvorą (dar žinomą kaip "efektas"), dmalloc , valgrind ir tt, tačiau dauguma jų yra daug lengviau dirbti pagal * nix nei Windows. „Valgrind“ yra juokingai lankstus: aš ištaisiau didelę serverio programinę įrangą su daugeliu problemų, susijusių su krūvos naudojimu.

Jei visa kita nepavyksta, galite pateikti savo pasauliniams operatoriams naują / ištrinti ir malloc / calloc / realloc perkrovą - kaip tai padaryti šiek tiek skirsis priklausomai nuo kompiliatoriaus ir platformos - ir tai bus maža investicija, tačiau tai gali būti maža, tačiau ji gali atsiskaityti ilgai perspektyva. Norimas sąrašas funkcijų turėtų atrodyti susipažinę su „dmalloc“ ir „electfence“ bei stebėtinai puiki knyga „ Rašymas kietuoju kodu“ :

  • valandinės vertės : leiskite šiek tiek daugiau vietos prieš ir po kiekvieno paskirstymo, laikydamiesi maksimalaus išlyginimo reikalavimo; užpildykite magiškus numerius (padeda perimti ir buferio buferio perpildymą ir atsitiktinį „laukinį“ rodiklį)
  • asign fill : užpildykite naujus asignavimus, kurių stebuklinga vertė yra ne 0 - „Visual C ++“ jau tai daro jums „Debug builds“ (tai padeda sugauti naudojant uninitialized vars)
  • laisvas užpildymas : užpildykite laisvosios atminties, kurios magija yra kitokia nei 0, norint pradėti segfault, jei ji daugeliu atvejų nuvertinama (tai padeda sugauti kabančius nurodymus)
  • su vėlavimu : neatleiskite atlaisvintos atminties į krūvą tam tikrą laiką, laikykite jį laisvai, bet neprieinama (tai padeda sugauti daugiau kabančių rodyklių, sugauti artimus dvigubus skaitmenis)
  • stebėjimas : kartais gali būti naudinga įrašyti, kur buvo paryškintas pasirinkimas

Atkreipkite dėmesį, kad mūsų vietinėje homebrew sistemoje (įterptam tikslui) sekame atskirai nuo daugelio kitų dalykų, nes prijungimo laikas yra daug didesnis.


Jei Jus domina daugiau priežasčių perkrauti šias platinimo funkcijas / operatorius, žr. Mano atsakymą į „Ar yra kokių nors priežasčių perkrauti naująjį naują operatorių ir ištrinti?“ ; apgaulingas savęs skatinimas, jame išvardyti kiti metodai, kurie yra naudingi sekant sugadinimo klaidų klaidas, ir kiti taikytini įrankiai.

117
18 июня '09 в 7:46 2009-06-18 07:46 Atsakymą davė leanderis birželio 18 d., 07:46, 2009-06-18 07:46

Galite aptikti daugelį korupcijos problemų, įtraukdami „Heap“ puslapį, skirtą jūsų programai. Norėdami tai padaryti, turite naudoti „gflags.exe“, kuri yra „Windows“ derinimo įrankių dalis

Paleiskite „Gflags.exe“ ir jūsų vykdomojo failo vaizdo failo parametruose pažymėkite >border=0

Dabar paleiskite exe ir prijunkite jį prie debugger. Įjungus „Heap Pages“ funkciją, programa išskaidoma į debugerį, kai įvyksta krūva.

32
18 июня '09 в 7:24 2009-06-18 07:24 atsakymą pateikė „ Canopus “ birželio 18 d., 07:24, 2009-06-18 07:24
13
06 авг. atsakymas pateikiamas Vijay 06 rug. 2009-08-06 12:17 '09, 12:17, 2009-08-06 12:17

Jei norite iš tikrųjų sulėtinti ir atlikti didelį vykdymo patikrinimą, pabandykite pridėti toliau nurodytus elementus main() arba lygiavertės versijos viršuje „Microsoft Visual Studio C ++“

 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_ALWAYS_DF ); 
10
14 янв. Dave Van Wagner atsakymas dėl sausio 14 d 2012-01-14 02:37 '12 at 2:37 2012-01-14 02:37

Kas gali sukelti šias klaidas?

Pavyzdžiui, neryškių dalykų atlikimas su atmintimi. rašykite po buferio galų arba rašykite į buferį po to, kai jis bus grąžintas į krūvą.

Kaip juos derinti?

Naudokite įrankį, kuris prideda automatinį sienos tikrinimą į jūsų vykdomąjį failą: pavyzdžiui, „valgrind“ „Unix“ sistemoje arba įrankis, pvz., „BoundsChecker“ („Wikipedia“ taip pat siūlo „Purify“ ir „Insure ++“) „Windows“.

Atminkite, kad tai sulėtins jūsų taikomąją programą, todėl jie gali būti netinkami, jei jūsų programa yra minkšta realiu laiku.

Kitas galimas derinimo / įrankio pajėgumas gali būti „MicroQuill HeapAgent“.

8
18 июня '09 в 3:09 2009-06-18 03:09 ChrisW atsakė birželio 18, 09 d. 3:09 2009-06-18 03:09

Vienas greitas patarimas, gautas iš laisvosios atminties prieigos aptikimo :

Jei norite greitai rasti klaidą, nekontroliuodami kiekvieno teiginio, kuris pasiekia blokavimo atmintį, po bloko išlaisvinimo galite nustatyti žymiklį į atmintį negaliojančia:

 #ifdef _DEBUG // detect the access to freed memory #undef free #define free(p) _free_dbg(p, _NORMAL_BLOCK); *(int*) = 0x666; #endif 
8
18 июня '09 в 11:54 2009-06-18 11:54 atsakymas pateikiamas StackedCrooked birželio 18, '09, 11:54 2009-06-18 11:54

Geriausias įrankis, kurį aš suradau naudingas ir dirbo kiekvieną kartą, yra kodo peržiūra (su gerais kodų recenzentais).

Be kodo patikrinimo, pirmiausia išbandysiu „ Heap“ puslapį . „Heap“ puslapis užtrunka kelias sekundes, kad sukonfigūruotų, ir, jei pasisekė, gali nustatyti jūsų problemą.

Jei nesate laimėję „Heap“ puslapyje, atsisiųskite „Microsoft“ derinimo įrankius „Windows“ ir sužinokite, kaip naudoti „WinDbg“. Atsiprašau, aš negalėjau suteikti jums daugiau konkrečios pagalbos, bet daugialypės korupcijos krūvos derinimas yra daugiau meno nei mokslas. „Google“ „persekioti pelną“ ir turėtumėte rasti daug straipsnių.

5
18 июня '09 в 7:20 2009-06-18 07:20 atsakymą pateikė „ Shing Yip “ birželio 18 d., 07:20, 2009-06-18 07:20

Taip pat galite patikrinti, ar nesate susietas su dinamine ar statine C runtime biblioteka, jei jūsų DLL failai yra susieti su statine C runtime biblioteka, DLL failuose yra atskirų krūvų.

Todėl, jei turite sukurti objektą viename DLL ir pabandyti ją išlaisvinti kitame DLL, gausite tą patį pranešimą, kurį matote aukščiau. Ši problema paminėta kitame klausime apie kamino perpildymą, atlaisvinant kitai DLL priskirtą atmintį .

4
04 февр. atsakymas yra dreadpirateryan 04 vasaris. 2011-02-04 04:20 '11 at 4:20 2011-02-04 04:20

Jei šios klaidos atsiranda atsitiktinai, yra didelė tikimybė, kad susidursite su duomenų lenktynėmis. Patikrinkite: ar keičiate bendrų atminties rodykles iš skirtingų sričių? „Intel Thread Checker“ gali padėti aptikti tokias problemas kelių sriegių programoje.

3
18 июня '09 в 20:39 2009-06-18 20:39 atsakymas pateikiamas Vladimirui Obrizanui birželio 18 d., 09:39 2009-06-18 20:39

Kokias paskirstymo funkcijas naudojate? Neseniai gavau panašią klaidą naudojant „Heap“ stiliaus pasirinkimo funkciją.

Paaiškėjo, kad klaidingai sukūriau krūva su HEAP_NO_SERIALIZE parinktimi. Tai labai supaprastina krūvos darbą be sriegio saugos. Tai yra našumo pagerinimas, kai jis naudojamas teisingai, bet niekada neturėtų būti naudojamas, jei naudojate HeapAlloc programą daugiaukelėje programoje [1]. Tai paminėsiu tik todėl, kad jūsų pranešime paminėta daugialypė programa. Jei naudojate HEAP_NO_SERIALIZE bet kur, pašalinkite ją ir greičiausiai išspręsite problemą.

[1] Yra tam tikrų situacijų, kai tai yra teisėta, tačiau tai reikalauja, kad skambintumėte į „Heap *“ ir, paprastai, tai netaikoma daugiakrypčiai programoms.

3
18 июня '09 в 3:25 2009-06-18 03:25 atsakymą pateikė JaredPar birželio 18 d. 09:25 2009-06-18 03:25

Be įrankių paieškos, pagalvokite apie galimo kaltininko suradimą. Ar yra kokių nors komponentų, kuriuos jūs naudojate, galbūt ne parašėte, kad galbūt nebuvo suprojektuotas ir išbandytas darbui daugiapakopėje aplinkoje? Arba tiesiog tai, ką jūs nežinote, dirbo tokioje aplinkoje.

Paskutinį kartą tai įvyko su manimi, tai buvo privatus paketas, kuris sėkmingai buvo naudojamas daugelį metų. Tačiau pirmą kartą šioje įmonėje ji buvo naudojama iš .NET žiniatinklio paslaugos (kuri yra daugiapakopė). Tai buvo - jie melavo, kad kodas yra saugus siūlams.

1
18 июня '09 в 3:29 2009-06-18 03:29 atsakymą pateikė Johnas Saundersas birželio 18 d., 09:29 2009-06-18 03:29

Turėjau panašią problemą - ir atrodė gana atsitiktinai. Gal kažkas buvo sugadinta kūrimo rinkmenose, bet baigiau jį ištaisyti, iš pradžių išvaliau projektą ir tada jį atkurdavau.

Taigi, be kitų pirmiau pateiktų atsakymų:

Kas gali sukelti šias klaidas? Kažkas sugadintas surinkimo faile.

Kaip juos derinti? Projekto valymas ir atstatymas. Jei tai yra nustatyta, tai tikriausiai yra problema.

0
31 окт. Marty 31 d 2016-10-31 01:18 '16 at 1:18 2016-10-31 01:18

Galite naudoti „VC CRT Heap-Check“ makrokomandas _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF arba _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .

0
07 нояб. Atsakymas pateikiamas KindDragon 07.11 . 2011-11-07 14:28 '11 at 14:28 2011-11-07 14:28

Norėčiau pridėti savo patirtį. Per pastarąsias dienas nusprendžiau nukopijuoti šią klaidą į savo paraišką. Mano konkrečiu atveju kodo klaidos buvo:

  • Pašalinus elementus iš STL kolekcijos per iteraciją (manau, kad „Visual Studio“ yra debugo vėliavų, kad sužlugdytumėte šiuos dalykus, aš sugriebau juos peržiūrint kodą)
  • Tai sunkiau, aš jį padalijau etapais:
    • Iš gimtojo C ++ gijos eikite į valdomą kodą
    • Control.Invoke žemėje skambinkite „ Control.Invoke ir ištrinkite valdomą objektą, kuris apgaubia savo objektą, su kuriuo susietas atgalinis ryšys.
    • Kadangi objektas vis dar gyvas savo gijos viduje (jis bus užblokuotas atgaliniame Control.Invoke iki „ Control.Invoke end“). Turiu paaiškinti, kad naudoju „ boost::thread , todėl naudoju nario funkciją kaip siūlų funkciją.
    • Sprendimas . Naudokite „ Control.BeginInvoke (mano GUI sukuriama naudojant „Winforms“), kad natūralus srautas galėtų baigtis prieš tai, kai objektas sunaikinamas (atšaukimo tikslas tiksliai praneša apie srauto pabaigą ir objektas gali būti sunaikintas).
0
23 мая '12 в 19:40 2012-05-23 19:40 atsakymą dario_ramos pateikė gegužės 23 d., 12 val. 19:40 2012-05-23 19:40