2016-03-23 6 views
3

MSVC'ye yapılan en son güvenlik güncelleştirmelerine uymak için bazı "eski" kodları güncelleştirmeye çalışıyorum ve _vsnprintf ile _vsnprintf_s arasında geçiş yapmakta sorun yaşıyorum. Özellikle Gerekli arabellek uzunluğunu güvenli bir şekilde alma _vsnprintf_s

, gerekli büyüklükte bir tamponu ( return value + 1) tahsis sonucu elde sayım/uzunluk için boş bir tampon maddesi ile _vsnprintf ve sıfır çağrı ve daha sonra, yeni olarak ayrılmış tamponu ile tekrar _vsnprintf çağrı ve bilinen doğru boyutta:

size_t length = _vsntprintf(nullptr, 0, mask, params); 
TCHAR *final = new TCHAR [length + 1]; 
_vsntprintf(final, length + 1, mask, params); 

Bu davranış documented on MSDN olup:

sayı ile belirtilen tampon boyutu formatı ve argptr tarafından belirtilen çıkış taşıyacak kadar büyük değilse vsnprintf'nin dönüş değeri, sayımın yeterince büyük olması durumunda yazılacak karakter sayısıdır. Dönüş değeri sayım-1'den büyükse, çıktı kesildi.

_vsnprintf_s, ancak its documentation does not contain the same ile aynı şeyi yapmaya çalışıyorum. Depolama verileri depolamak için gerekli ve bir sonlandırıcı boş sizeOfBuffer aşarsa yerine Parametre Doğrulama anlatıldığı gibi sayımı _TRUNCATE olmadıkça, geçersiz parametre işleyicisi,, çağrıldığında

diyor dize kadar bu durumda arabellek sığacak şekilde yazılır ve -1 döndürülür.

aşağıdaki zaten dışarı çalışılıyor:

size_t length = _vsntprintf_s(nullptr, 0, 0, mask, params); 

Bu sıfır "uzunluğunda" ile sonuçlanır. Eğer _TRUNCATE yılında geçerseniz (-1) sayımı yerine, aşağıdaki onaylama işlemi başarısız olarak:

İfade:! tampon = nullptr & & buffer_count> 0

Ben _set_invalid_parameter_handler geçersiz kılmak mümkündür tahmin ve bir şekilde uzunluğun ne olması gerektiğini buluyoruz, ama daha kolay bir yolu olmalı?

+0

Bu, hiçbir C kodudur. – Olaf

+0

@Olaf Üzgünüz, bu C++ olmalıydı. Bu yazım hatası kaçırdığım 'security-enhanced-crt' etiketi hakkında endişeleniyordum. Gerçekten de bunun aşağılayıcı olduğunu düşünmüyor musun? –

+0

'size_t length = _vsntprintf (nullptr, 0, 0, mask, params) satırında, '_vsntprintf_s' demek istediniz? – TriskalJM

cevap

6
size_t length = _vscprintf(mask, va_list); 
TCHAR *final = new TCHAR [length + 1]; 
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list); 
+1

Bu mükemmel. Güzel ve temiz bir çözüm. '_vscprintf'' _vsnprintf_s' sayfasında, imho belgelenmelidir. –

-1

Nasıl uzunluğunu elde etmek için "kurallarını ihlal" değil kendi vsnprintf varyantı haddeleme hakkında: [büyük olasılıkla] Eğer sizeof(buf) az olmalıdır edilecektir iade yana

int 
printf_size(const char *fmt,int count,va_list ap) 
{ 
    char buf[2000000]; 
    int len; 

    len = vsnprintf_s(buf,sizeof(buf),count,fmt,ap); 

    return len; 
} 

ince.

Veya yapın:

int 
printf_size(const char *fmt,int count,va_list ap) 
{ 
    char *buf; 
    int siz; 
    int len; 

    for (siz = 2000000; ; siz <<= 1) { 
     buf = malloc(siz); 
     len = vsnprintf_s(buf,siz,count,fmt,ap); 
     free(buf); 
     if (len < siz) 
      break; 
    } 

    return len; 
} 

Veya, bir yerden işlevini yapıyor:

int 
sprintf_secure(char **buf,const char *fmt,int count,va_list ap) 
{ 
    char *bp; 
    int siz; 
    int len; 

    for (siz = 2000000; ; siz <<= 1) { 
     bp = malloc(siz); 
     len = vsnprintf_s(bp,siz,count,fmt,ap); 
     if (len < siz) 
      break; 
    } 

    bp = realloc(bp,len + 1); 

    *buf = bp; 

    return len; 
} 
+0

Öneri için teşekkürler, ancak birisi her defasında fonksiyonumu aradığında 4MiB veriyi rasgele ayırmak bir çeşit aşırı sıkıcıdır. –

+0

Eh, sadece [ilk] yığın sürümünü kullanın. Tahsis yok. 2MB'lık bir tamponla [10.000 bol olmalı], maksimum yığın sınırını aşmamalıdır. Veya sprintf_secure ancak 1000 (veya 100) ile başlar - kullanılan gerçek uzunluğu izleyerek dinamik olarak ayarlanabilen bir ayar parametresidir. BTW, yorumunuza dayanarak, sadece "cprintf" in aynı nedenlerden dolayı kullanılamayacağını varsaydım, aksi halde muhtemelen cevabı yayınlayamazdım. –

+0

Hayır, güvenli crt işlevleri yalnızca önceden ayrılmış bir arabelleğe yazmayı içeren işlemleri değiştirir. Bir tamsayı döndüren vscprintf gibi bir işlev etkilenmez. –