2009-03-20 10 views
7

a bug in Firefox (यहां तक ​​कि नए बीटा और माइनफील्ड रिलीज़ में भी) है जो कुछ फ़ाइलों की कैशिंग को रोकता है क्योंकि उनके कैश हैश में कुंजी बनाने के लिए एल्गोरिदम की वजह से। Here is a link to the source code of the functionफ़ायरफ़ॉक्स कैश हैश कुंजी पीढ़ी एल्गोरिदम बग

मैं यह सुनिश्चित करना चाहता हूं कि मेरी सभी साइट की फ़ाइलों को कैश किया जा सके। हालांकि, मुझे समझ में नहीं आता कि क्यों उनके हैशिंग फ़ंक्शन विशिष्ट यूआरएल के लिए अद्वितीय कुंजी बनाने में विफल रहता है। मुझे आशा है कि कोई भी psuedo-code या जावा में mal फ़ंक्शन का वर्णन कर सकता है।

डेवलपर्स के लिए यह बग ठीक होने तक अद्वितीय यूआरएल सुनिश्चित करने के लिए उपयोगिता बनाना अच्छा होगा।


संपादित करें: वहाँ कुछ बहुत ही उपयोगी जवाब दिया गया है, फिर भी, मैं और कदम-दर-कदम मदद इन कैश उलझनों से जांच करने के लिए एक उपयोगिता बनाना होगा। कुछ जावा कोड प्राप्त करना बहुत अच्छा होगा जो फ़ायरफ़ॉक्स बनाने वाली कुंजियों को पुन: उत्पन्न कर सकता है। इसलिए, इस सवाल पर एक बक्षीस खोलना।


संपादित करें 2: यहाँ एक आंशिक रूप से काम कर रहे जावा बंदरगाह (लिखित processing का उपयोग) है। नीचे परीक्षणों पर ध्यान दें; उम्मीद के अनुसार पहले तीन काम, लेकिन दूसरों को नहीं। मुझे हस्ताक्षरित/हस्ताक्षरित इनट्स के बारे में कुछ संदेह है। सुझाव?

// 
// the bad collision function 
// http://mxr.mozilla.org/mozilla/source/netwerk/cache/src/nsDiskCacheDevice.cpp#240 
// 

//248 PLDHashNumber 
//249 nsDiskCache::Hash(const char * key) 
//250 { 
//251  PLDHashNumber h = 0; 
//252  for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s) 
//253   h = PR_ROTATE_LEFT32(h, 4)^*s; 
//254  return (h == 0 ? ULONG_MAX : h); 
//255 } 

// 
// a java port... 
// 

String getHash(String url) 
{ 

//get the char array for the url string 
char[] cs = getCharArray(url); 

int h = 0; 

//for (const PRUint8* s = (PRUint8*) key; *s != '\0'; ++s) 
for (int i=0; i < cs.length; i++) 
{ h = PR_ROTATE_LEFT32(h, 4)^cs[i]; 
} 

//looks like the examples above return something in hex. 
//if we get matching ints, that is ok by me. 
//but for fun, lets try to hex the return vals? 
String hexVal = hex(h); 
return hexVal; 
} 

char[] getCharArray(String s) 
{ 
    char[] cs = new char[s.length()]; 
    for (int i=0; i<s.length(); i++) 
    { 
    char c = s.charAt(i); 
    cs[i] = c; 
    } 

    return cs; 
} 

// 
// how to PR_ROTATE_LEFT32 
// 

//110 /* 
//111 ** Macros for rotate left and right. The argument 'a' must be an unsigned 
//112 ** 32-bit integer type such as PRUint32. 
//113 ** 
//114 ** There is no rotate operation in the C Language, so the construct 
//115 ** (a << 4) | (a >> 28) is frequently used instead. Most compilers convert 
//116 ** this to a rotate instruction, but MSVC doesn't without a little help. 
//117 ** To get MSVC to generate a rotate instruction, we have to use the _rotl 
//118 ** or _rotr intrinsic and use a pragma to make it inline. 
//119 ** 
//120 ** Note: MSVC in VS2005 will do an inline rotate instruction on the above 
//121 ** construct. 
//122 */ 
//... 
//128 #define PR_ROTATE_LEFT32(a, bits) _rotl(a, bits) 


//return an int (32 bit). what do we do with the 'bits' parameter? ignore? 
int PR_ROTATE_LEFT32(int a, int bits) 
{ return (a << 4) | (a >> (32-bits)); 
} 

// 
// examples of some colliding hashes 
// https://bugzilla.mozilla.org/show_bug.cgi?id=290032#c5 
// 

//$ ./hashit "ABA/xxx.aba" 
//8ffac222 
//$ ./hashit "XyZ/xxx.xYz" 
//8ffac222 
//$ ./hashit "CSS/xxx.css" 
//8ffac222 
//$ ./hashit "JPG/xxx.jpg" 
//8ffac222 

//$ ./hashit modules_newsfeeds/MenuBar/MenuBar.css 
//15c23729 
//$ ./hashit modules_newsfeeds/ListBar/ListBar.css 
//15c23729 

//$ ./hashit modules_newsfeeds/MenuBar/MenuBar.js 
//a15c23e5 
//$ ./hashit modules_newsfeeds/ListBar/ListBar.js 
//a15c23e5 



// 
// our attempt at porting this algorithm to java... 
// 

void setup() 
{ 

String a = "ABA/xxx.aba"; 
String b = "CSS/xxx.css"; 
String c = "CSS/xxx.css"; 
String d = "JPG/xxx.jpg"; 

println(getHash(a)); //yes 8ffac222 
println(getHash(b)); //yes 8ffac222 
println(getHash(c)); //yes 8ffac222 
println(getHash(d)); //no [??] FFFFFF98, not 8ffac222 

println("-----"); 

String e = "modules_newsfeeds/MenuBar/MenuBar.css"; 
String f = "modules_newsfeeds/ListBar/ListBar.css"; 

println(getHash(e)); //no [??] FFFFFF8C, not 15c23729 
println(getHash(f)); //no [??] FFFFFF8C, not 15c23729 

println("-----"); 

String g = "modules_newsfeeds/MenuBar/MenuBar.js"; 
String h = "modules_newsfeeds/ListBar/ListBar.js"; 

println(getHash(g)); //yes [??] FFFFFF8C, not a15c23e5 
println(getHash(h)); //yes [??] FFFFFF8C, not a15c23e5 

} 
+0

ईमानदारी से मुझे लगता है कि आप इस बारे में बहुत अधिक चिंता कर रहे हैं। क्या आप किसी प्रकार की समस्या का सामना कर रहे हैं, या यह सभी समयपूर्व अनुकूलन है? –

+0

समस्या का सामना करना पड़ रहा है। : -/ – jedierikb

+0

समस्या का और स्पष्टीकरण: यह सुनिश्चित करने के लिए रणनीतियों के साथ आने की आवश्यकता है कि हजारों फाइलों को सही ढंग से कैश किया गया हो। अभी, वे नहीं हैं। यह सुनिश्चित करने के लिए कि वे कैश-सक्षम हैं, सभी फ़ाइल नामों को प्री-प्रोसेस करना चाहते हैं। – jedierikb

उत्तर

5

यहाँ कैसे एल्गोरिथ्म काम करता है:

initialize hash to 0 
for each byte 
    shift hash 4 bits to left (with rotate) 
    hash = hash XOR character 
नेत्रहीन

(16 -बिट संस्करण):

00110000    = '0' 
    00110001   = '1' 
     00110010  = '2' 
      00110011 = '3' 
0100   0011 = '4' 
00110101    = '5' 
==================== 
01000110001000010000 (and then this will be 'rotated' 
         so that it lines up with the end) 
giving: 
     00100001000001000110 

क्या इसका मतलब यह है कि आप एक ही लंबाई के तार है और प्राय: एक ही कर रहे हैं, तो कम से कम एक मामले में, एक चार के निचले 4 बिट्स और के ऊपरी 4 बिट्स अगले चार xor एक दूसरे को अद्वितीय होना चाहिए। हालांकि, किसी तालिका में 32 बिट संख्या को चिपकाने की विधि कभी कमजोर हो सकती है, जिसका अर्थ यह है कि स्ट्रिंग (मॉड 8 वर्ण) में किसी विशेष स्थान के निचले 4 xor upper4 को अद्वितीय होना आवश्यक है।

6

मैं क्या सिर्फ बगजिला प्रविष्टि पढ़ने के समझ में से, बग प्रकट होता है जब दो अलग-अलग समस्याएं होती हैं:

  1. उनके हैश एल्गोरिथ्म यूआरएल है कि "पर्याप्त समान" हैं के लिए टकराव उत्पन्न करता है। बग से "समान परिचित" का मतलब है कि प्रत्येक 4 वर्ण (या शायद 8) यूआरएल समान हैं, और
  2. हैश टकराव से निपटने के लिए उनका तर्क विफल रहता है क्योंकि उन्होंने पिछले यूआरएल को उसी हैश वैल्यू के साथ फ़्लश नहीं किया है अभी तक डिस्क पर।

तो मूल रूप से, यदि आपके पास दो बहुत समान यूआरएल वाले पृष्ठ हैं तो यह फ़ायरफ़ॉक्स के कुछ संस्करणों पर हो सकता है। यह आमतौर पर अलग-अलग पृष्ठों पर नहीं होगा, मैं उम्मीद करता हूं, तब से एफएफ के पास टाइमिंग इश्यू से बचने वाली डिस्क में प्रविष्टियों को फ्लश करने का समय होगा।

तो यदि आपके पास एकाधिक संसाधन (स्क्रिप्ट, छवियां, आदि) हैं जो सभी एक ही पृष्ठ से लोड होते हैं, तो सुनिश्चित करें कि उनके पास 9 वर्ण हैं जो पूरी तरह से अलग हैं। ?

+0

हाँ, मैंने बाइट्स पढ़े हैं जहां यह बिट्स होना चाहिए और मानसिक रूप से वर्णों में परिवर्तित होना चाहिए। नीचे के अन्य लोगों के पास हैशिंग एल्गोरिदम की अच्छी व्याख्या है। –

+0

एक क्वेरी स्ट्रिंग का सुझाव अच्छा है, लेकिन पूर्व-प्रक्रिया के रूप में मेरी फ़ाइलों के लिए अद्वितीय यूआरएल सुनिश्चित करना चाहता हूं। – jedierikb

+0

इसके अलावा, रनटाइम पर एक यादृच्छिक क्वेरीस्ट्रिंग जोड़ने के लिए कैशिंग की आवश्यकता होती है जो कहीं भी यादृच्छिक क्वेरीस्ट्रिंग को एक पैटर्न विकसित कर रहा है जो टकरा नहीं जाता है। – jedierikb

1

पहले: एक तरह से आप यह सुनिश्चित कर सकते हैं डेटा के एक यादृच्छिक बिट, की तरह कुछ के साथ एक क्वेरी स्ट्रिंग (है कि आप ध्यान न दें) जोड़कर है , आप अनजाने में सभी तारों को अनन्य रूप से नहीं कर सकते हैं (जाहिर है, (निश्चित आकार) पूर्णांक से अधिक तार हैं, इसलिए टकराव होना चाहिए)। आपके पास एक हैशटेबल हो सकता है जो डेटा के सभी सेट (जैसे आपकी सभी फाइलें) रख सकता है, लेकिन इसे प्राप्त करने के लिए, आपको हैशटेबल का कोड बदलना होगा, न कि हैशिंग फ़ंक्शन।

दूसरा, मैं हैशिंग समारोह आप पोस्ट के साथ एक समस्या देखते हैं, इस हिस्से में:

PR_ROTATE_LEFT32(h, 4) 

यह वास्तव में 4 तरह से, h के रोटेशन (मैं इस पर जांच न की हो) करता है घूर्णन हैं कि तारों में दो 8-बाइट (मुझे लगता है कि 32-बिट हैश) भागों को बदल दिया गया है (उदाहरण के लिए xxxxxxxxyyyyyyyy बनाम yyyyyyyyxxxxxxxx) के बराबर हैश होगा। यदि आप कुछ अपेक्षाकृत हैश आकार (। उदाहरण के लिए 5), यह केवल लंबाई की बदली भागों के लिए क्या होगा करने के लिए प्रधानमंत्री के लिए इसे बदल 32.

+0

मुझे लगता है कि वह सवाल पूछ रहा है कि 'मैं इस गरीब हैश फ़ंक्शन के आसपास कैसे काम कर सकता हूं', 'मैं एक बेहतर हैश फ़ंक्शन कैसे बना सकता हूं' – FryGuy

0

आप वास्तविक बग के बारे में स्पष्ट रूप से गलत हैं। निश्चित रूप से, हैश एल्गोरिदम की अविश्वसनीय रूप से खराब पसंद के कारण हैश टकराव हैं। लेकिन हैश (x) = 1 भी वर्णित समस्याओं का कारण नहीं बनता है। यह केवल पहली बाल्टी के माध्यम से एक ओ (एन) लिंक सूची सूची में ओ (1) लुकअप को बदल देगा।

वास्तविक समस्या यह है कि फ़ायरफ़ॉक्स हैश टकराव से निपटने में विफल रहता है। इसलिए इसे सभी यूआरएल का एक परिपूर्ण हैश की आवश्यकता है। दुर्भाग्य से "सभी यूआरएल" आपके नियंत्रण के बाहर एक सेट है।

+0

मैं कम से कम यह सुनिश्चित कर सकता हूं कि मेरी साइट का "सब यूआरएल" का सबसेट नहीं है मेरी साइट के लिए एक पूर्व प्रसंस्करण उपयोगिता के साथ टक्कर। – jedierikb

2

इस बग अपनी साइट के लिए एक प्रमुख मुद्दा था: http://worldofsolitaire.com

मैं .htaccess फ़ाइल में एक सशर्त नियम है कि Firefox उपयोगकर्ताओं के लिए साइट पर छवियों के सभी कैशिंग निष्क्रिय हैं का उपयोग करके एक लंबे समय पहले उसके चारों ओर काम किया । यह करने के लिए एक भयानक चीज थी, लेकिन उस समय मैं फ़ायरफ़ॉक्स के भीतर बग को ट्रैक नहीं कर सका और साइट को थोड़ा धीमा होना डुप्लिकेट/दूषित छवियों को दिखाने से बेहतर है।

जब मैं लिंक किए गए बग में पढ़ता हूं कि इसे नवीनतम फ़ायरफ़ॉक्स रिलीज़ में तय किया गया था, तो मैंने 1 9 अप्रैल 200 9 (कल) को सशर्त बदल दिया ताकि केवल फ़ायरफ़ॉक्स 2 उपयोगकर्ताओं के लिए कैशिंग अक्षम हो सके।

कुछ घंटों बाद मुझे फ़ायरफ़ॉक्स 3 उपयोगकर्ताओं (पुष्टि) से 10 से अधिक ई-मेल प्राप्त हुए हैं कि वे डुप्लिकेट छवियां देख रहे थे। तो यह समस्या अभी भी फ़ायरफ़ॉक्स 3 में एक समस्या है।

मैंने एक साधारण लिनक्स परीक्षण प्रोग्राम बनाने का निर्णय लिया जो मुझे यूआरएल की जांच करने की अनुमति देगा कि वे एक ही कैश हैश कुंजी उत्पन्न कर रहे हैं या नहीं।

किसी भी Linux सिस्टम में संकलित करने के लिए: जी ++ -ओ ffgenhash ffgenhash.cpp

यहाँ कोड है (ffgenhash दायर करने के लिए बचाने के लिए।सीपीपी)

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

#define ULONG_MAX 0xFFFFFFFF 
#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) 

unsigned long ffgenhash(const char * key) 
{ 
    unsigned long h=0; 

    for(const unsigned char * s = (unsigned char *) key; *s != '\0'; ++s) 
    { 
     h = PR_ROTATE_LEFT32(h, 4)^*s; 
    } 

    return (h==0 ? ULONG_MAX : h); 
} 

int main(int argc, char ** argv) 
{ 
    printf("%d\n", ffgenhash(argv[1])); 
    return 0; 
} 

आप देख सकते हैं, यहाँ दो वास्तविक जीवन यूआरएल है कि एक ही कैश हैश कुंजी उत्पन्न कर रहे हैं:

./ffgenhash "http://worldofsolitaire.com/decks/paris/5/12c.png" 
1087949033 
./ffgenhash "http://worldofsolitaire.com/decks/paris/5/13s.png" 
1087949033 

जब से मैं पहले से लोड एक जावास्क्रिप्ट पाश में इन छवियों का उपयोग करने की कोशिश कर कुछ प्रकार के खाली < स्क्रिप्ट > टैग वर्कअराउंड यहां संभव नहीं है।

वास्तव में मुझे लगता है कि मेरा एकमात्र वास्तविक समाधान है कि किसी अद्वितीय कैश हैश कुंजी उत्पन्न करने के लिए फ़ायरफ़ॉक्स उपयोगकर्ताओं के लिए URL को संशोधित करना है। तो यही वह दृष्टिकोण है जिसका मैं उपयोग करूंगा।

वैसे, मैं एक फायरबग अतिरिक्त बनाने के लिए आधा प्रलोभन हूं जो साइट द्वारा लोड किए गए सभी संसाधनों की जांच करेगा और साइट पर दो संसाधन एक सामान्य हैश कुंजी साझा करते हैं तो बड़ी त्रुटि दें ताकि डेवलपर को पता हो। पिछले कुछ सालों में उन छवियों के साथ अजीब चीज़ों को देखने के लिए बहुत अच्छा होगा :)

1

यह एसम्बायंस के हैश जेनरेटर का संशोधित संस्करण है जो 64- बिट प्लेटफ़ॉर्म:

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

#define ULONG_MAX 0xFFFFFFFF 
#define PR_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) 

unsigned int ffgenhash(const char * key) { 
    unsigned int h=0; 
    for(const unsigned char * s = (unsigned char *) key; *s != '\0'; ++s) { 
     h = PR_ROTATE_LEFT32(h, 4)^*s; 
    } 
    return (h==0 ? ULONG_MAX : h); 
} 

int main(int argc, char ** argv) { 
    printf("%u\n", ffgenhash(argv[1])); 
    return 0; 
}