2017-07-06 15 views
5

पहले चेतावनी: मैं यहां जिज्ञासा से बाहर हैकिंग कर रहा हूं। मेरे पास नीचे क्या कर रहा है करने के लिए मेरे पास कोई विशिष्ट कारण नहीं है!पायथन

नीचे MacOS 10.12.5

मैं चारों ओर अजगर के साथ हैकिंग था पर Python 2.7.13 पर किया जाता है और मैंने सोचा कि यह देखने के लिए कि मैं

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 

nonblocking fcntl करने के लिए कॉल है stdout बनाया क्या हुआ दिलचस्प होगा निश्चित रूप से सफल मैं फिर बड़ी मात्रा में डेटा लिखने की कोशिश करता हूं (ओएसएक्स पर एक पाइप के अधिकतम बफर आकार से बड़ा - जो 65536 बाइट्स है)। मैं इसे विभिन्न तरीकों से करता हूं और अलग-अलग परिणाम प्राप्त करता हूं, कभी-कभी अपवाद करता हूं, कभी-कभी जो असफल लगता है।

प्रकरण 1

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
try: 
    sys.stdout.write("A" * 65537) 
except Exception as e: 
    time.sleep(1) 
    print "Caught: {}".format(e) 

# Safety sleep to prevent quick exit 
time.sleep(1) 

यह हमेशा अपवाद Caught: [Errno 35] Resource temporarily unavailable फेंकता है। मुझे लगता है कि समझ में आता है। उच्च स्तरीय फ़ाइल ऑब्जेक्ट रैपर मुझे बता रहा है कि लिखने की कॉल विफल रही है।

प्रकरण 2

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
try: 
    sys.stdout.write("A" * 65537) 
except Exception as e: 
    print "Caught: {}".format(e) 

# Safety sleep to prevent quick exit 
time.sleep(1) 

यह कभी कभी अपवाद फेंकता Caught: [Errno 35] Resource temporarily unavailable या कभी कभी भी इसका अपवाद नहीं पकड़ा है और मैं निम्नलिखित उत्पादन देखें:

close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 

प्रकरण 3

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
try: 
    sys.stdout.write("A" * 65537) 
except Exception as e: 
    print "Caught: {}".format(e) 

# Safety sleep to prevent quick exit 
time.sleep(1) 

print "Slept" 

यह कभी-कभी अपवाद Caught: [Errno 35] Resource temporarily unavailable फेंकता है या कभी-कभी कोई अपवाद नहीं पकड़ा जाता है और मुझे बस "स्लीप्ट" दिखाई देता है। ऐसा लगता है कि print आईएनजी द्वारा "सो" मैं प्रकरण 2. से

प्रकरण 4

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
try: 
    os.write(sys.stdout.fileno(), "A" * 65537) 
except Exception as e: 
    print "Caught: {}".format(e) 

# Safety sleep to prevent quick exit 
time.sleep(1) 

हमेशा ठीक त्रुटि संदेश नहीं मिलता है!

प्रकरण 5

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 
try: 
    print os.write(sys.stdout.fileno(), "A" * 65537) 
except Exception as e: 
    print "Caught: {}".format(e) 

# Safety sleep to prevent quick exit 
time.sleep(1) 

यह कभी कभी ठीक है या कभी कभी close failed in file object destructor त्रुटि संदेश प्रिंट करता है।

मेरा सवाल यह है कि यह इस तरह पाइथन में क्यों विफल हो जाता है? क्या मैं यहाँ कुछ मौलिक रूप से बुरा कर रहा हूं - या तो पाइथन या सिस्टम स्तर पर?

ऐसा लगता है कि लिखने से पहले ही लिखना बहुत जल्द लिख रहा है जब लेखन पहले से विफल हुआ है त्रुटि संदेश का कारण बनता है। त्रुटि अपवाद नहीं प्रतीत होती है। कोई विचार नहीं है कि यह कहां से आ रहा है।

एनबी।मैं सी में समकक्ष प्रोग्राम लिख सकता हूं और यह ठीक काम करता है:

#include <stdio.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <sys/fcntl.h> 
#include <unistd.h> 

int main(int argc, const char * argv[]) 
{ 
    const size_t NUM_CHARS = 65537; 
    char buf[NUM_CHARS]; 

    // Set stdout non-blocking 
    fcntl(fileno(stdout), F_SETFL, O_NONBLOCK); 

    // Try to write a large amount of data 
    memset(buf, 65, NUM_CHARS); 
    size_t written = fwrite(buf, 1, NUM_CHARS, stdout); 

    // Wait briefly to give stdout a chance to be read from 
    usleep(1000); 

    // This will be written correctly 
    sprintf(buf, "\nI wrote %zd bytes\n", written); 
    fwrite(buf, 1, strlen(buf), stdout); 
    return 0; 
} 
+0

मुझे लगता है कि * * समस्या यह है कि गैर-अवरुद्ध आईओ के साथ, 'os.write' को कॉल करने से पहले लिखना है लौट सकते है पूरा करें, और चूंकि यह आपके सरल परीक्षण कार्यक्रम को समाप्त करता है, इसलिए लिखने से पहले 'sys.stdout' भी बंद किया जा सकता है। ध्यान दें कि आपका सी प्रोग्राम इंतजार कर रहा है ('नींद (1000) ') जहां आपका पायथन कोड नहीं है। प्रतिक्रिया के लिए – chepner

+0

धन्यवाद। मुझे पायथन कोड का एक और पूर्ण स्निपेट पोस्ट करना चाहिए था। मेरे पास लिखने के बाद 'time.sleep (1) 'था और इससे कोई फर्क नहीं पड़ता :( –

+0

आपका ओएस क्या है? आप पाइथन को' स्ट्रेस 'जैसी चीज़ों के तहत चलाने का प्रयास कर सकते हैं और देख सकते हैं कि सिस्टम कॉल किस प्रकार की जाती है। –

उत्तर

1

यह दिलचस्प है। कुछ चीजें है कि मैं अब तक मिल गया है कर रहे हैं:

केस 1

इसका कारण यह है sys.stdout.write या तो स्ट्रिंग के सभी लिख सकते हैं या एक अपवाद है, जो वांछित व्यवहार का उपयोग करते समय नहीं है फेंक होगा O_NONBLOCK। जब write पर अंतर्निहित कॉल EAGAIN (ओएस एक्स पर एरर्नो 35) लौटाता है, तो शेष डेटा के साथ फिर से प्रयास किया जाना चाहिए। os.write इसके बजाए उपयोग किया जाना चाहिए, और यह सुनिश्चित करने के लिए कि सभी डेटा लिखे गए हैं, वापसी मूल्य की जांच की जानी चाहिए।

इस कोड काम करता है के रूप में उम्मीद:

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 

def stdout_write(s): 
    written = 0 
    while written < len(s): 
     try: 
      written = written + os.write(sys.stdout.fileno(), s[written:]) 
     except OSError as e: 
      pass 

stdout_write("A" * 65537) 

केस 2

मुझे लगता है यह त्रुटि संदेश के कारण https://bugs.python.org/issue11380 है कि:

close failed in file object destructor: 
sys.excepthook is missing 
lost sys.stderr 

मुझे यकीन है कि क्यों नहीं कर रहा हूँ इसे कभी-कभी बुलाया जाता है। ऐसा इसलिए हो सकता है क्योंकि printexcept कथन में है जो उसी stdout का उपयोग करने का प्रयास कर रहा है, जो कि एक लेख अभी विफल हुआ है।

प्रकरण 3

यह इसी तरह की है केस 1. करने के लिए इस कोड को हमेशा मेरे लिए काम करता है:

fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) 

def stdout_write(s): 
    written = 0 
    while written < len(s): 
     try: 
      written = written + os.write(sys.stdout.fileno(), s[written:]) 
     except OSError as e: 
      pass 

stdout_write("A" * 65537) 

time.sleep(1) 

print "Slept" 

प्रकरण 4

आप os.write की वापसी मान की जाँच सुनिश्चित करें , मुझे संदेह है कि पूर्ण 65537 बाइट सफलतापूर्वक लिखे नहीं जा रहे हैं।

प्रकरण 5

इस मामले के समान है 2.

+0

इनपुट @Tim के लिए धन्यवाद। मुझे पिछले हफ्ते में इस पर वापस आने का मौका नहीं मिला था। मैंने इस मुद्दे पर बहुत अधिक समय लगाया है। संक्षेप में, 'sys.stdout.write' से अपवाद पूरी तरह से अपेक्षित है (स्रोत को देखते हुए)। 'file.write' एक अपवाद उठाएगा यदि या तो, कम बाइट अपेक्षित से लिखा गया था या अंतर्निहित फ़ाइल संभाल पर 'आतंक' गैर-शून्य लौटाता है। तो रहस्य त्रुटि संदेश के आसपास निश्चित रूप से है। मैंने स्रोत को देखा है और अपना खुद का निर्माण डीबग किया है और मैंने अभी तक 100% रूट कारण की पहचान की है (अगली टिप्पणी जारी रखेगी)। –

+0

त्रुटि व्याख्याकर्ता शट डाउन के दौरान होती है, जब व्याख्याकर्ता std फ़ाइल हैंडल बंद कर रहा है (जो यह क्रम में करता है, 1, 0, 2 यानी stdout, stdin, stderr)। यह stdout का समापन है जो विफल रहता है (असुरक्षित रूप से)। विशेष रूप से 'fclose' विफल रहता है। यह तब होता है जब 'stdout' के लिए अंतर्निहित' FILE' हैंडल के '_flags' में' __SERR' सेट होता है (जो ओएसएक्स के लिए एक libc कार्यान्वयन विवरण है)। मैंने सोचा कि यह बंद होने पर फ्लश कॉल के दौरान हो सकता है लेकिन ऐसा नहीं लगता है। वैसे भी, अजगर "अच्छी तरह से" व्यवहार कर रहा है जिसमें यह त्रुटि को प्रिंट कर रहा है जब यह 'stdout' को ठीक से बंद करने में विफल रहता है। हालांकि, ... –

+0

मैं पूरी तरह से समझ नहीं पा रहा हूं कि उस स्थिति में 'फ़ाइल' हैंडल क्या रखता है। मैंने सी और कोई भाग्य में repro करने की कोशिश की है। मैंने व्याख्याता में भी हैक किया है और कोई भी बुद्धिमान नहीं है। मुझे लगता है कि मैं * समस्या को ढूंढ सकता हूं, लेकिन मैं अभी भी खरगोश छेद को गहरा कर चुका हूं इसलिए थोड़ी देर के लिए दूर देखने की जरूरत है :) मैं इस पर जिज्ञासा से वापस आ सकता हूं। यह बेहद संभव है कि यहाँ अजगर के साथ एक अजीब किनारे का मामला बग है, लेकिन यहां तक ​​कि अगर ऐसा कोई संभावना नहीं है तो कोई भी ऐसा करेगा! –