2012-09-11 15 views
9

benim OpenPGP modülünde https://github.com/singpolyma/OpenPGP-Haskell/blob/master/Data/OpenPGP.hs içindedir hata için basit bir test koşucu vardır:Bu kod niçin optomizasyonlarla açık veya kapalı olarak farklı davranıyor?

module Main where 

import Data.OpenPGP 
import Data.Binary (encode, decode) 

packet = EmbeddedSignaturePacket (signaturePacket 2 168 ECDSA SHA256 [] [SignatureCreationTimePacket 1013401916,IssuerPacket "36FE856F4219F1C7"] 48065 [MPI 4,MPI 11,MPI 60,MPI 69,MPI 37,MPI 33,MPI 18,MPI 72,MPI 41,MPI 36,MPI 43,MPI 41,MPI 53,MPI 9,MPI 53,MPI 35,MPI 3,MPI 40,MPI 14,MPI 79,MPI 1,MPI 4,MPI 51,MPI 23,MPI 62,MPI 62,MPI 62,MPI 7,MPI 68,MPI 51,MPI 13,MPI 49,MPI 8,MPI 64,MPI 32,MPI 50,MPI 59,MPI 17,MPI 43,MPI 12,MPI 67,MPI 5,MPI 67,MPI 5,MPI 25,MPI 63,MPI 0,MPI 53,MPI 2,MPI 36,MPI 83,MPI 39,MPI 54,MPI 65,MPI 54,MPI 35,MPI 62,MPI 63,MPI 26,MPI 4,MPI 82,MPI 57,MPI 85,MPI 71,MPI 43,MPI 77]) 

main = print $ decode (encode packet) == packet 

Eğer derlemek Eğer bununla (ghc 7.4.1 üzerine): Bu beklendiği gibi çalıştığını

ghc -O0 -fforce-recomp --make t.hs 

(yani, True yazdırır), ancak böyle derlemek eğer:

ghc -O1 -fforce-recomp --make t.hs 

veya bu:

ghc -O2 -fforce-recomp --make t.hs 

False yazdıracaktır.

Herhangi bir uzantı (CPP'nin önemsiz kullanımı hariç) veya düşük düzeyli veya güvensiz aramalar kullanmıyorum ve davranış benim kitaplığımdan değil bağımlılıktan oluşmalı, çünkü yalnızca burada yeniden derlenmiş kodum var .

+5

Bu hatayı GHC'de yeniden üretebilirim 7.4.2 –

+1

Bu hatayı gözlemlediğinizde ikili veya tahıl kullanıyor musunuz? –

cevap

5

Bu, kodunuzdaki bir hatadır. Biz MPI 0 kodlarsanız bytes' böylece bytes = B.singleton 0 boştur ve bu nedenle bytes `B.index` 0 0.

Ama logBase 2 0-Infinity olduğunu ve floor sadece iyi-olan, şimdi

MPI 63,MPI 0,MPI 53 
     ^^^^^ 

ve

instance BINARY_CLASS MPI where 
    put (MPI i) = do 
     put (((fromIntegral . B.length $ bytes) - 1) * 8 
       + floor (logBase (2::Double) $ fromIntegral (bytes `B.index` 0)) 
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
       + 1 :: Word16) 
    putSomeByteString bytes 
    where 
    bytes = if B.null bytes' then B.singleton 0 else bytes' 
    bytes' = B.reverse $ B.unfoldr (\x -> 
        if x == 0 then Nothing else 
          Just (fromIntegral x, x `shiftR` 8) 
      ) (assertProp (>=0) i) 

düşünün sonlu değerler için tanımlanmıştır (hedef türün aralığı dahilinde).

Optimisations olmadan derleme yaparken, floor, decodeFloat aracılığıyla bit modelini kullanır. Daha sonra floor (logBase 2 0), tüm standart sabit genişlikli tamsayı türleri için 0 sağlar.

İyileştirmelerle, bir yeniden yazma kuralı aktiftir ve floor, donanımın yaptığı her şeyi x86 olarak bildiren double2Int# numaralı primopu kullanır. x86-64, bu bit modelinden bağımsız olarak, bildiğim kadarıyla minBound :: Int.İlgili kod

floorDoubleInt :: Double -> Int 
floorDoubleInt (D# x) = 
    case double2Int# x of 
     n | x <## int2Double# n -> I# (n -# 1#) 
     | otherwise    -> I# n 

ve tabii, -Infinity < int2Double minBound arasında, yani değer genellikle maxBound olduğunu minBound - 1, olur.

bir yanlış sonuç neden Tabii

, şimdi bu yana MPI 0 için put 0 olur ise "uzunluk" ve "uzunluk" alanına sonra koymak 0 bayt sonraki MPI ait "uzunluğunun" bir parçası olarak yorumlanır .

+0

Teşekkürler! "Zemin" in davranışının -O ile değişmesini beklemiyordum, ama yine de benim varsayımlarımda bir hatam olduğu doğru. – singpolyma

+1

Yeniden yazma kurallarının davranışı değiştirdiği birkaç yer var. Çoğunlukla doğru sonuç bulunmadığı zaman, 'floor' et al. Için aralık dışı değerler gibi. Ancak bazen anlamlı sonuçlara sahip yerlerde bile, ör. '(realToFrac :: Float -> Double) (0/0)' optimisations olmadan '-5.104235503814077e38' üretir, optimisations ile NaN'. Dil raporu "realToFrac = fromRational" yazıyor. ilkini üreten toRational'. 'Rasyonel' NaN'leri ve sonsuzlukları gerçekten idare edemediğinden, bu dönüşümde onları tedavi etmenin iyi bir yolu yoktur ve bunlar kelleğe girer. Primop onları korur. –

+0

NaN dahil olduğunda işler her zaman çok daha eğlencelidir ... –

5

Bu sorun, MPI için BINARY_CLASS örneğinizle ilgilidir.

newtype MPI = MPI Integer deriving (Show, Read, Eq, Ord) 
instance BINARY_CLASS MPI where 
    put (MPI i) = do 
    put (fromIntegral $ B.length bytes :: Word16) 
    putSomeByteString bytes 
    where 
    bytes = if B.null bytes' then B.singleton 0 else bytes' 
    bytes' = B.pack . map (read . (:[])) $ show i 
    get = do 
    length <- fmap fromIntegral (get :: Get Word16) 
    bytes <- getSomeByteString length 
    return (MPI $ read $ concatMap show $ B.unpack bytes) 

düzeltmeleri sorun: Ben

main = do 
    print packet 
    print (decode (encode packet) :: SignatureSubpacket) 
    print $ decode (encode packet) == packet 

değiştirirseniz ben (-o2 ile derlenmiş) çıkışı

EmbeddedSignaturePacket (SignaturePacket {version = 2, signature_type = 168, key_algorithm = ECDSA, hash_algorithm = SHA256, hashed_subpackets = [], unhashed_subpackets = [SignatureCreationTimePacket 1013401916,IssuerPacket "36FE856F4219F1C7"], hash_head = 48065, signature = [MPI 4,MPI 11,MPI 60,MPI 69,MPI 37,MPI 33,MPI 18,MPI 72,MPI 41,MPI 36,MPI 43,MPI 41,MPI 53,MPI 9,MPI 53,MPI 35,MPI 3,MPI 40,MPI 14,MPI 79,MPI 1,MPI 4,MPI 51,MPI 23,MPI 62,MPI 62,MPI 62,MPI 7,MPI 68,MPI 51,MPI 13,MPI 49,MPI 8,MPI 64,MPI 32,MPI 50,MPI 59,MPI 17,MPI 43,MPI 12,MPI 67,MPI 5,MPI 67,MPI 5,MPI 25,MPI 63,MPI 0,MPI 53,MPI 2,MPI 36,MPI 83,MPI 39,MPI 54,MPI 65,MPI 54,MPI 35,MPI 62,MPI 63,MPI 26,MPI 4,MPI 82,MPI 57,MPI 85,MPI 71,MPI 43,MPI 77], trailer = Chunk "\168" (Chunk "<gI<" Empty)}) 
EmbeddedSignaturePacket (SignaturePacket {version = 2, signature_type = 168, key_algorithm = ECDSA, hash_algorithm = SHA256, hashed_subpackets = [], unhashed_subpackets = [SignatureCreationTimePacket 1013401916,IssuerPacket "36FE856F4219F1C7"], hash_head = 48065, signature = [MPI 4,MPI 11,MPI 60,MPI 69,MPI 37,MPI 33,MPI 18,MPI 72,MPI 41,MPI 36,MPI 43,MPI 41,MPI 53,MPI 9,MPI 53,MPI 35,MPI 3,MPI 40,MPI 14,MPI 79,MPI 1,MPI 4,MPI 51,MPI 23,MPI 62,MPI 62,MPI 62,MPI 7,MPI 68,MPI 51,MPI 13,MPI 49,MPI 8,MPI 64,MPI 32,MPI 50,MPI 59,MPI 17,MPI 43,MPI 12,MPI 67,MPI 5,MPI 67,MPI 5,MPI 25,MPI 63,MPI 0,MPI 0,MPI 339782829898145924110968965855122255180100961470274369007196973863828909184332476115285611703086303618816635857833592912611149], trailer = Chunk "\168" (Chunk "<gI<" Empty)}) 

bu daha kolay uygulanması için MPI örneğini değiştirme bkz.

Sorun kaynağı olabilecek birkaç şey var. Kodunuzun doğru olması mümkündür (Bu ya da başka bir şekilde kontrol etmedim). Bu durumda GHC, bir yerdeki taşma/alt akıma yol açan birtakım geçersiz dönüşümler gerçekleştiriyordur. Ayrıca, kodunuzun yalnızca belirli optimizasyonlarla karşılaşılan yanlış bir şey yapması da mümkündür.

İlgili konular