2012-04-26 5 views
5

मेरे पास यह डेल्फी 7 एप्लिकेशन में यह फ़ंक्शन है, जो तब तक बहुत अच्छा काम करता है जब तक कि मैंने प्रोजेक्ट में FastMM4 v4.99 शामिल नहीं किया। एक बार शामिल होने के बाद, फास्टएमएम 4 ने निम्न त्रुटि संदेश उठाया: "फास्टएमएम को फ्रीमेम ऑपरेशन के दौरान एक त्रुटि मिली है। ब्लॉक फूटर दूषित हो गया है।" फ्रीमैम लाइन में निष्पादन रोकता है।फास्टएमएम 4 कहता है "ब्लॉक फूटर दूषित हो गया है"

function BinaryFieldToArrayOfWord(aBinaryField : TVarBytesField; 
            out aArrValues : TArrWord) : Boolean; 
var 
    p : Pointer; 
begin 
    if not aBinaryField.IsBlob then 
    begin 
    GetMem(p, aBinaryField.DataSize);  
    try 
     if aBinaryField.GetData(p) then   
     begin 
     // do something 
     end; 
    finally 
     FreeMem(p, aBinaryField.DataSize); 
    end; 
    end; // if 
end; 

सबसे पहले मैंने सोचा था कि वहाँ समारोह में एक बग होना चाहिए, लेकिन यह व्यावहारिक रूप से डेल्फी 7 मदद में इस TField.GetData विधि उदाहरण के रूप में एक ही है:

{ Retrieve the "raw" data from Field1 } 
with Field1 do 
begin 
    if not IsBlob { this does not work for BLOB fields } 
    begin 
    { Allocate space } 
    GetMem(MyBuffer, DataSize); 
    try 
     if not GetData(MyBuffer) then 
     MessageDlg(DisplayName + ' is NULL', mtInformation, [mbOK], 0) 
     else 
     { Do something with the data }; 
    finally 
     { Free the space } 
     FreeMem(MyBuffer, DataSize); 
    end; 
    end; 
end; 

मैं पर पाया इंटरनेट जो उपर्युक्त त्रुटि संदेश अक्सर होता है क्योंकि डेटा के लिए पर्याप्त स्थान नहीं है। इसलिए मैंने मेमोरी ब्लॉक के आकार में वृद्धि की और त्रुटि संदेश गायब हो गया और समारोह अपेक्षित के रूप में काम किया। कुछ प्रयोग के बाद, मैं पता लगा कि 2 बाइट्स की आवश्यकता है और पर्याप्त:

GetMem(p, aBinaryField.DataSize + 2); 

    FreeMem(p, aBinaryField.DataSize + 2); 

हालांकि यह मेरी समस्या हल, मैं इस समाधान मैं इसकी पृष्ठभूमि पता नहीं है के रूप में पूरी तरह से आराम नहीं कर रहा हूँ। इस संदेश के कारण को जानना अच्छा लगेगा। क्या FastMM4 को अपने स्वयं के पाद लेख के लिए अतिरिक्त 2 बाइट की आवश्यकता है?

अद्यतन: डिबगिंग के साथ एक दिन बिताने के बाद, अब मुझे विश्वास है कि डेल्फी 7 TField.GetData विधि में एक बग है। यह आवंटित स्मृति ब्लॉक से परे 2 शून्य बाइट लिखता है। मैंने इसे FastMM4 के साथ और बिना कोशिश की, और यह दोनों मामलों में ओवरराइट करता है (इसलिए यह FastMM4 त्रुटि नहीं है)। मैंने टीवीरबाइट्सफ़िल्ल्ड के रूप में फ़ील्ड टाइपकास्टिंग के साथ भी कोशिश की, कोई फर्क नहीं पड़ता। यहां कोड है जिसका मैंने विस्तृत टिप्पणियों के साथ उपयोग किया, जिसमें परिणाम शामिल हैं। मेरा एकमात्र शेष प्रश्न: क्या उन्होंने बाद में डेल्फी में इस बग को सही किया है?

procedure TfrmMain_PBC_TH.btnDEBUGClick(Sender: TObject); 
    type 
    TArrBytes = array of Byte; 
    var 
    p  : Pointer; 
    qryTest : TADOQuery; 
    begin 
    qryTest := TADOQuery.Create(Application); 
    try 
     // The type of the TQM_BinaryData.BinData column in the MSSQL database is a  varbinary(7900). 
     // Load the #168 binary data record. It contains exactly 7900 bytes, and the value of each byte is 255 
     qryTest.Connection := MainConn; 
     qryTest.SQL.Add('SELECT [BinData] FROM [TQM_BinaryData] WHERE [Id] = 168'); 
     qryTest.Open; 

     // Allocate the memory block for this. 
     GetMem(p, qryTest.FieldByName('BinData').DataSize); 
     // DataSize is 7902 because all TVarBytesFields have 2 byte prefix in Delphi, containing the data length. 
     // So the size of the allocated memory block is 7902 bytes - we are correct so far. 
     try 
     // Values of the first four bytes beyond the end of the memory block (memory thrash at this point) before GetData: 
     // TArrBytes(p)[7902] = 96 
     // TArrBytes(p)[7903] = 197 
     // TArrBytes(p)[7904] = 219 
     // TArrBytes(p)[7905] = 43 

     // Critical point: get the data from the field with the Delphi GetData method 
     qryTest.FieldByName('BinData').GetData(p); 

     // Values after GetData: 
     // TArrBytes(p)[0] = 220 TArrBytes(p)[0] and TArrBytes(p)[1] contains the length of the binary data 
     // TArrBytes(p)[1] = 30  it is correct as 30 * 256 + 220 = 7900 
     // TArrBytes(p)[2] = 255 actual data starts 
     // TArrBytes(p3[2] = 255  
     // ... 
     // TArrBytes(p)[7900] = 255 
     // TArrBytes(p)[7901] = 255 actual data ends 
     // TArrBytes(p)[7902] = 0  changed from 96! 
     // TArrBytes(p)[7903] = 0  changed from 197! 
     // TArrBytes(p)[7904] = 219 no change 
     // TArrBytes(p)[7905] = 43  no change 
     finally 
     // Here FastMM4 throws the block footer corrupt error because GetData modified the 2 bytes after the allocated memory block 
     FreeMem(p); 
     end; 

     qryTest.Close; 
    finally 
     qryTest.Free; 
    end; 
    end; 

एक डाटा ब्रेकप्वाइंट जोड़ने के बाद, कॉल स्टैक है:

@FillChar(???,???,???) 
    TDataSet.DataConvert($7D599770,$12F448,$7D51F7F0,True) 
    VarToBuffer 
    TCustomADODataSet.GetFieldData($7D599770,$7D51F7F0,True) 
    TField.GetData($7D51F7F0,True) 
    TfrmMain_PBC_TH.btnDEBUGClick($7FF7A380) 
    TControl.Click 
    TButton.Click 

उत्तर

5

FastMM ब्लॉक के अंत है कि आप आवंटित पर कुछ स्मृति आवंटित करता है और मूल्यों वहाँ जाना जाता है लिखता है। फिर, जब आप विघटित करते हैं, तो फास्टएमएम जांचता है कि उन मानों की अपेक्षा की जाती है। यदि नहीं, तो आप जो त्रुटि देखते हैं उसे उठाया जाता है क्योंकि FastMM जानता है कि आपका कोड स्मृति ब्लॉक के अंत से परे लिख रहा है।

तो, कोशिश/आखिरकार ब्लॉक के अंदर कुछ स्मृति के ब्लॉक के अंत से परे लिख रहा है। और यही कारण है कि इसका आकार बढ़ाना FastMM त्रुटि को हटा देता है। उस कोड को देखे बिना, हम यह नहीं बता सकते कि वास्तव में क्या गलत है और आपको समस्या को हल करने के लिए कुछ डिबगिंग करने की आवश्यकता होगी।

आप अपने "समाधान" से चिंतित होने का काफी अधिकार हैं। परीक्षण और त्रुटि कार्यक्रम के लिए कभी भी एक उचित तरीका नहीं है। आपको पता होना चाहिए कि आपका प्रोग्राम ब्लॉक के अंत से परे क्यों लिख रहा है।

ऐसा करने का एक तरीका यह है कि इस ब्लॉक के अंत से तुरंत पते के लिए डेटा ब्रेकपॉइंट सेट करना है। इससे डीबगर को ब्लॉक के अंत से परे लिखने वाले कोड पर तोड़ने के लिए मजबूर किया जाएगा।

एक तरफ के रूप में, आपको फ्रीमेम में दूसरा पैरामीटर पारित करने की आवश्यकता नहीं है। ऐसा करने से आपके कोड को बनाए रखने के लिए कठिन बना दिया जाता है और बिल्कुल कोई उद्देश्य नहीं होता है। फ्रीमेम को सिर्फ पॉइंटर पास करें।

+0

डीबगिंग के दौरान मैंने कोशिश की/आखिरकार ABinaryField.GetData (p) पंक्ति को छोड़कर सबकुछ बाहर टिप्पणी की, इसलिए मेरा अंतिम कोड बिल्कुल जैसा दिखता था। FreeMem से दूसरे पैरामीटर को हटाने से इस समस्या का समाधान नहीं हुआ।लेकिन अगर फास्टएमएम मेरे आवंटित मेमोरी ब्लॉक के अंत में कुछ ज्ञात मान लिखता है, और फिर मैं ब्लॉक को पूरी तरह से किसी अन्य डेटा के साथ भरता हूं (GetData यह IMHO करता है) तो ज्ञात मान ओवरराइट हो जाएंगे, भले ही मैंने केवल आवंटित ब्लॉक का उपयोग किया हो , है न? तो +2 बाइट उन FastMM ज्ञात मानों के लिए है। – Almandine

+0

मैंने यह नहीं कहा कि फ्रीमेम का दूसरा पैरामीटर समस्या को हल करेगा, बस यह पास करने के लिए व्यर्थ था। ब्लॉक अंत से परे कुछ लिख रहा है। –

+0

"लेकिन अगर फास्टएमएम मेरे आवंटित मेमोरी ब्लॉक के अंत में कुछ ज्ञात मान लिखता है, और फिर मैं ब्लॉक को पूरी तरह से किसी अन्य डेटा (गेटडाटा करता हूं) के साथ भरता हूं तो ज्ञात मान ओवरराइट हो जाएंगे, भले ही मैंने केवल उपयोग किया आवंटित ब्लॉक, है ना? " ज़रुरी नहीं। क्या होता है, आप कहते हैं कि 10 बाइट्स पूछते हैं, लेकिन फास्टएमएम 14 आवंटित करता है। यह आपको इस ब्लॉक की शुरुआत में एक सूचक देता है जिसमें आपको लगता है कि इसमें 10 बाइट हैं। लेकिन फिर अंत में अतिरिक्त 4 बाइट्स में ज्ञात मान लिखते हैं। अगर उन्हें ओवरराइट करें, फास्टएमएम को एक बग मिला है। अंत से परे कुछ लिख रहा है। –