2015-02-22 7 views
21

मैंने पाया कि कुछ लोग और पुस्तकें जैसे संदर्भ बताते हैं कि p != NULL और p पिछले आवंटन से उत्पत्ति (उदा। malloc), तो realloc(p, 0) जीएनयू/लिनक्स पर free(p) के बराबर है। वास्तव में है कि ढंग (जोर मेरा भविष्य में) में इस शोध man realloc राज्यों का समर्थन करने के लिए:क्या realloc (पी, 0) वास्तव में glibc में मुफ्त (पी) शामिल है?

realloc() फ़ंक्शन आकार बाइट्स ptr द्वारा की ओर इशारा किया स्मृति ब्लॉक का आकार बदल जाता है। सामग्रियों को से लेकर पुराने और नए आकारों तक की क्षेत्र की शुरुआत में अपरिवर्तित किया जाएगा। यदि नया आकार पुराने आकार से बड़ा है, तो जोड़ा गया स्मृति प्रारंभ नहीं होगा। यदि पीआरटी न्यूल है, तो कॉल आकार के सभी मूल्यों के लिए मॉलोक (आकार) के बराबर है; यदि आकार शून्य के बराबर है, और पीआरटी पूर्ण नहीं है, तो कॉल मुफ्त (पीआरटी) के बराबर है। जब तक पीआरटी न्यूल है, तो इसे पहले कॉल द्वारा malloc(), कॉलोक() या realloc() पर वापस कर दिया जाना चाहिए। यदि क्षेत्र को स्थानांतरित किया गया था, तो एक मुक्त (पीआरटी) किया जाता है।

आप this question में मिल सकता है के रूप में, सी स्टैंडर्ड ठीक परिभाषित नहीं करता है कि क्या होने चाहिए और वास्तविक व्यवहार कार्यान्वयन परिभाषित किया गया है। अधिक विशेष रूप से:

C11 §7.22.3/p1 मेमोरी प्रबंधन कार्यों का कहना है: या तो एक अशक्त:

अनुरोध किया अंतरिक्ष के आकार शून्य है, व्यवहार कार्यान्वयन परिभाषित किया गया है सूचक वापस, या व्यवहार ऐसा लगता है जैसे आकार कुछ nonzero मान थे, सिवाय इसके कि लौटाया गया पॉइंटर किसी ऑब्जेक्ट तक पहुंचने के लिए उपयोग नहीं किया जाएगा।

और सी 11 §7.22.3.5 realloc समारोह शामिल हैं:

3) (...) नई वस्तु के लिए स्मृति आवंटित नहीं किया जा सकता है, पुराने वस्तु है और मूल्य को अपरिवर्तित नहीं किया गया

4) realloc समारोह नई वस्तु (जो वर्ष वस्तु के सूचक के रूप में एक ही मूल्य हो सकता है), या एक अशक्त सूचक अगर नई वस्तु आवंटित नहीं किया जा सका के लिए सूचक देता है।

मैं स्मृति चेकर mcheck की मदद से वास्तविक व्यवहार पता लगाने के लिए कुछ बुनियादी कोड लिखा है, कि glibc साथ आपूर्ति की है:

#include <mcheck.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    int a = 5; 
    int *p, *q; 

    mtrace(); 

    p = malloc(sizeof(int)); 
    q = &a; 

    printf("%p\n", (void *) p); 
    printf("%p\n", (void *) q); 

    q = realloc(p, 0); 

    printf("%p\n", (void *) p); 
    printf("%p\n", (void *) q); 

    return 0; 
} 

और परिणाम हैं:

$ gcc -g check.c 
$ export MALLOC_TRACE=report 
$ ./a.out 
0xfd3460 
0x7ffffbc955cc 
0xfd3460 
(nil) 
[[email protected] workspace]$ mtrace a.out report 

Memory not freed: 
----------------- 
      Address  Size  Caller 
0x0000000000fd3460  0x4 at /home/grzegorz/workspace/check.c:12 

आप के रूप में q देख सकते हैं NULL पर सेट किया गया था। ऐसा लगता है कि free() वास्तव में नहीं बुलाया गया था। वास्तव में यह नहीं किया जा सकता जब तक कि मेरी व्याख्या गलत है: के बाद से reallocNULL सूचक वापस आ गया है, नई वस्तु आवंटित नहीं किया जा सकता था किया गया, जिसका मतलब है कि:

वर्ष वस्तु पुनः आवंटित की जाती है और नहीं है अपने मूल्य अपरिवर्तित है

क्या यह सही है? या तो एक अशक्त सूचक है:

+11

'रीयलोक (पीआरटी, 0)' के बारे में शब्द 'मुक्त (पीआरटी)' के बराबर है जो पॉज़िक्स में उपयोग किया जाता है, लेकिन [आधिकारिक पॉसिक्स 'realloc' संदर्भ] (http: //pubs.opengroup। संगठन/onlinepubs/9699919799/कार्यों/realloc.html) अब सी मानक से भाषा का उपयोग करता है। हालांकि, पीओएसईक्स मानक कहता है, "अगर' realloc() 'एक शून्य सूचक देता है, तो पी द्वारा इंगित स्थान मुक्त नहीं किया गया है"। –

उत्तर

9

संपादित करें: आपका glibc 2.18 में एक पूर्व-2.18 प्रतीत होता है, 2.18 में एक बग mtrace में तय किया गया था (here देखें)। 2.20 ग्लिबैक पर आपका टेस्ट प्रोग्राम रिपोर्ट करता है: "कोई मेमोरी लीक नहीं है।"

free ग्लिब में कॉल किया जाता है। वर्तमान glibc 2.21 (here और here) के स्रोतों से:

/* 
    REALLOC_ZERO_BYTES_FREES should be set if a call to 
    realloc with zero bytes should be the same as a call to free. 
    This is required by the C standard. Otherwise, since this malloc 
    returns a unique pointer for malloc(0), so does realloc(p, 0). 
*/ 

#ifndef REALLOC_ZERO_BYTES_FREES 
#define REALLOC_ZERO_BYTES_FREES 1 
#endif 

void * 
__libc_realloc (void *oldmem, size_t bytes) 
{ 
    mstate ar_ptr; 
    INTERNAL_SIZE_T nb;   /* padded request size */ 

    void *newp;    /* chunk to return */ 

    void *(*hook) (void *, size_t, const void *) = 
    atomic_forced_read (__realloc_hook); 
    if (__builtin_expect (hook != NULL, 0)) 
    return (*hook)(oldmem, bytes, RETURN_ADDRESS (0)); 

#if REALLOC_ZERO_BYTES_FREES 
    if (bytes == 0 && oldmem != NULL) 
    { 
     __libc_free (oldmem); return 0; 
    } 
#endif 
+0

यह शून्य के रूप में 'REALLOC_ZERO_BYTES_FREES' को परिभाषित करने वाले कुछ शीर्षलेख (शायद वैकल्पिक रूप से) को अस्वीकार नहीं करता है। कोई हेडर ऐसा नहीं कर रहा है, लेकिन मुझे लगता है कि आपको इसका जवाब देना चाहिए। – hvd

+1

@hvd परिभाषित 'REALLOC_ZERO_BYTES_FREES' का प्रभाव केवल तब होता है जब आप * बिल्डिंग * ग्लिबक होते हैं। इसका कोई प्रभाव नहीं पड़ता है जब आप केवल लाइब्रेरी का उपयोग कर रहे हैं। –

+0

@ 一 二三 वेल डुह। :) मैं हेडर का जिक्र कर रहा हूं कि ग्लिबैक स्वयं का उपयोग कर रहा है। यह पूर्ण स्रोत फ़ाइल नहीं है। पूर्ण स्रोत फ़ाइल में '# शामिल' निर्देश शामिल हैं। बग ट्रैकर का हवाला देते हुए – hvd

2

realloc() के व्यवहार के रूप में जब पारित किया जा रहा 0 से आकार implenentation परिभाषित किया गया है ...

अनुरोध किया अंतरिक्ष के आकार शून्य है, व्यवहार कार्यान्वयन परिभाषित किया गया है लौटा, या व्यवहार यह है कि आकार कुछ nonzero मान थे, सिवाय इसके कि लौटा सूचक का उपयोग किसी ऑब्जेक्ट तक पहुंचने के लिए नहीं किया जाएगा।

... पोर्टेबल बराबर

को
void * p = malloc(1); 
free(p); 

void * p = malloc(1); 
p = realloc(p, 0) 
free(p); /* because of the part after the "or" as quoted above. 

स्मृति संतुलन भी बाद में होना चाहिए की जरूरत है।

अद्यतन को कवर realloc() की "त्रुटि" मामला: http://code.woboq.org/userspace/glibc/malloc/memusage.c.html#realloc:

void * p = malloc(1); 
{ 
    void * q = realloc(p, 0); 
    p = q ?q :p; 
} 
free(p); /* because of the part after the "or" as quoted above. 
+5

यदि 'realloc' एक पूर्ण सूचक देता है, तो आप उस पॉइंटर को खो देते हैं जिसे मुक्त करने की आवश्यकता होती है :( –

+0

आपका मतलब पोर्टेबल' void * p = malloc (1) के बराबर है; realloc (p, 0); 'सही? – immibis

+2

@BenVoigt अगर 'realloc' एक पूर्ण सूचक देता है, तो आप नहीं जानते कि पुराने सूचक को मुक्त करना है या नहीं! – immibis

2

glibc यहाँ realloc कोड पर एक नज़र डालें। आप लाइन 434 पर देखेंगे कि free को आकार 0 के समय कहा जाता है।

+4

क्या आप सुनिश्चित हैं कि यह * * * ग्लिब के' realloc' के कार्यान्वयन 'है? मुझे स्रोतों को काफी उलझन में मिला है, और इस स्रोत फ़ाइल में टिप्पणी है (पहले में लाइन) "प्रोफ़ाइल ढेर और चल रहे प्रोग्राम के स्मृति उपयोग को ढेर करें।" एक और फाइल है, 'malloc/malloc.c', जिसमें '__libc_realloc' है, जिसे' realloc 'के लिए उपनाम दिया गया है। वास्तव में उस कार्यान्वयन में एक कंपाइलर swi होता है टीएच ''REALLOC_ZERO_BYTES_FREES' कहा जाता है जो इस मामले में व्यवहार को प्रभावित करता है। – dyp

+0

आप सही हैं। Http://osxr.org/glibc/source/malloc/malloc.c में लाइनें 571--574 देखें। यह नहीं पता कि यह कब सेट है या नहीं ... –

+0

http://www.atnf.csiro.au/computing/software/casacore/casacore-1.2.0/doc/html/ में लाइन 217-2-220 देखें malloc_8h_source.html। इस प्रतीकों को परिभाषित करना शून्य आकार आवंटन पर 'malloc' व्यवहार के साथ स्थिरता का विषय है। –

7

हालांकि "लौटे NULL" मामले की मेरी intepretation, सही होने के लिए (नीचे देखें मेरे संपादन) glibc डेवलपर्स decided यह पिछले C89 के अनुरूप रखने के लिए लगता है मानक और सी 99/सी 11 के अनुरूप होने के लिए खारिज कर दिया गया:

कोई रास्ता नहीं बदला जाएगा।इस प्रकार यह हमेशा के लिए लागू किया गया है। सी मौजूदा अभ्यास दस्तावेज करना चाहिए। बदलना इसका मतलब स्मृति रिसाव शुरू करना होगा।

इसके अलावा mcheck संकेत, भ्रामक था के रूप में अन्य परीक्षण मामले से पता चला है कि स्मृति प्रभावी रूप से realloc द्वारा मुक्त है:

#include <malloc.h> 
#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    int *p, *q; 

    p = malloc(20 * sizeof(int)); 
    malloc_stats(); 

    putchar('\n'); 

    q = realloc(p, 0); 
    malloc_stats(); 

    return 0; 
} 

यहाँ, उत्पादन होता है:

$ gcc check.c 
$ ./a.out 
Arena 0: 
system bytes  =  135168 
in use bytes  =   96 
Total (incl. mmap): 
system bytes  =  135168 
in use bytes  =   96 
max mmap regions =   0 
max mmap bytes =   0 

Arena 0: 
system bytes  =  135168 
in use bytes  =   0 
Total (incl. mmap): 
system bytes  =  135168 
in use bytes  =   0 
max mmap regions =   0 
max mmap bytes =   0 

संपादित करें :

एचवीडी comment में इंगित किया गया है, आईएसओ/आईईसी वर्किंग ग्रुप में कुछ चर्चा हुई थी, जिसे Defect Report #400 के रूप में पूरा किया गया था। प्रस्तावित परिवर्तनों से सी मानक के भविष्य में संशोधन (या संभवतः सी 11 के लिए तकनीकी कोर्रिजेंडम 1) में glibc के मौजूदा अभ्यास की अनुमति हो सकती है।

क्या मैं वास्तव में के बारे में डॉ # 400 प्रस्ताव है:

उपधारा 7.31.12 एक नया पैरा (अनुच्छेद 2) में जोड़ें:

एक आकार तर्क के बराबर के साथ लागू realloc शून्य एक अश्लील सुविधा है।

+2

+1। मैंने इस मुद्दे को फिर से खोल दिया है क्योंकि निर्णय ग्लिब के पूर्व तानाशाह द्वारा किया गया था जो अब आगे बढ़ रहा है। –

+2

@ आर ..क्या कोई ग्लिबक बग है, यद्यपि? यदि मैं पढ़ रहा हूं [DR # 400] (http://open-std.org/JTC1/SC22/WG14/www/docs/dr_400.htm) सही ढंग से C90 और glibc व्यवहार को फिर से अनुमति देने के लिए सी बदल गया। या वह कभी स्वीकार नहीं किया गया था? – hvd

+0

@hvd: मुझे लगता है कि अगले टीसी में सी 11 में होगा, तो हो सकता है कि लोगों को खुश करने के लिए पर्याप्त हो। मुझे अभी भी लगता है कि यह भ्रमित है हालांकि। डीआर के लिए प्रस्तावित टीसी में किए गए पहले परिवर्तन से यह लगता है कि एनयूएलएल एक त्रुटि होने पर 'रीयलोक' के लिए केवल वैध वापसी मूल्य है। –

संबंधित मुद्दे