Diese Präsentation wurde erfolgreich gemeldet.
Die SlideShare-Präsentation wird heruntergeladen. ×

Price of an Error

Wird geladen in …3

Hier ansehen

1 von 32 Anzeige

Weitere Verwandte Inhalte

Diashows für Sie (20)

Ähnlich wie Price of an Error (20)


Weitere von Andrey Karpov (20)

Aktuellste (20)


Price of an Error

  1. 1. Price of an Error Andrey Karpov OOO "Program Verification Systems" (Co Ltd) karpov@viva64.com
  2. 2. Introducing the speaker • Andrey Nicolaevich Karpov, 1981 • scientific adviser in OOO "Program Verification Systems" (Co Ltd) • candidate of science (philosophy doctor) • MVP in Visual C++ • Intel Black Belt Software Developer • one of the PVS-Studio (C/C++ source code analyzer) founders. www.viva64.com
  3. 3. It is quite often that software developers have absolutely no clue about the cost of an error • I have no reliable statistics on an average cost of an error, as they are too diverse and can be discovered at different stages of production. • But, I know an average industry cost of a single line of source code. Try guessing it now. www.viva64.com
  4. 4. How much does it cost to write a single line of code? www.viva64.com
  5. 5. How much does it cost to write a single line of code? 28 $ www.viva64.com
  6. 6. Why is it so high? • Large-scale projects usually do not possess a huge number of newly written code. • Overheads are usually not taken into account. www.viva64.com
  7. 7. What developers often forget: • A software developer does not spend 100% of his working time on coding; • Taxes and bonuses; • Vacations and incapacity due to illness; • Maintenance (accountancy, administration, janitor); • Workspace environment, hardware, internet charges, rent, candies, paper for printer; • Software; • Etc. www.viva64.com
  8. 8. What am I getting at? • The price for an error is much higher than the programmer thinks it is. • If an employee wastes an hour because of an error, this hour will not be wasted by him alone. • This hour of unproductivity should be multiplied by a quite large factor. • If a bug gets its way to the QA guy, it is just as terrible as it can get. www.viva64.com
  9. 9. It is very important that the error be found at the earliest possible stage • The earlier an error is found, the lower will be a price for fixing it. • And here are some methods for an early detection: • Testing Driven Development; • Static code analysis; • Defensive programming. • All of these methods are complementary. www.viva64.com
  10. 10. We will discuss static code analysis and how you can protect yourself against several types of errors • I cannot mention all possible issues, but it will give you an excuse for self-perfection while writing your own code. • This experience is based upon checking over 200 open-source projects written on C and C++. The errors themselves are available here: http://www.viva64.com/en/examples/ www.viva64.com
  11. 11. How do developers view themselves Ho do I see developers
  12. 12. Last line effect • Similar to mountain-climbers; • This statistics was generated from our library when it contained about 1500 examples of errors. • I’ve detected 84 corresponding fragments. • In 43 cases, the error was on the last line of code. TrinityCore inline Vector3int32& operator+=(const Vector3int32& other) { x += other.x; y += other.y; z += other.y; return *this; } www.viva64.com
  13. 13. Last Line Effect Source Engine SDK inline void Init( float ix=0, float iy=0, float iz=0, float iw = 0 ) { SetX( ix ); SetY( iy ); SetZ( iz ); SetZ( iw ); } Chromium if (access & FILE_WRITE_ATTRIBUTES) output.append(ASCIIToUTF16("tFILE_WRITE_ATTRIBUTESn")); if (access & FILE_WRITE_DATA) output.append(ASCIIToUTF16("tFILE_WRITE_DATAn")); if (access & FILE_WRITE_EA) output.append(ASCIIToUTF16("tFILE_WRITE_EAn")); if (access & FILE_WRITE_EA) output.append(ASCIIToUTF16("tFILE_WRITE_EAn")); break; www.viva64.com
  14. 14. Last Line Effect qreal x = ctx->callData->args[0].toNumber(); Qt qreal y = ctx->callData->args[1].toNumber(); qreal w = ctx->callData->args[2].toNumber(); qreal h = ctx->callData->args[3].toNumber(); if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(w)) if (!strncmp(vstart, "ASCII", 5)) OpenSSL arg->format = ASN1_GEN_FORMAT_ASCII; else if (!strncmp(vstart, "UTF8", 4)) arg->format = ASN1_GEN_FORMAT_UTF8; else if (!strncmp(vstart, "HEX", 3)) arg->format = ASN1_GEN_FORMAT_HEX; else if (!strncmp(vstart, "BITLIST", 3)) arg->format = ASN1_GEN_FORMAT_BITLIST; www.viva64.com
  15. 15. Last Line Effect 1. The most simple one. One shold know about this effect and always check for it. 2. Impossible in real life. Use fewer Copy-Pastes. 3. Always align similar block of code, so that the error becomes immediately noticeable. 4. Use “tables”.0 10 20 30 40 50 1 2 3 4 5 www.viva64.com
  16. 16. Cases when table-style formatting can be utilized Asterisk static char *token_equivs1[] = { .... "KW_IF", "KW_IGNOREPAT", "KW_INCLUDES" "KW_JUMP", "KW_MACRO", "KW_PATTERN", .... }; www.viva64.com
  17. 17. Cases when table-style formatting can be utilized static char *token_equivs1[] = { .... "KW_IF" , "KW_IGNOREPAT" , "KW_INCLUDES" "KW_JUMP" , "KW_MACRO" , "KW_PATTERN" , .... }; Asterisk static char *token_equivs1[] = { .... "KW_IF", "KW_IGNOREPAT", "KW_INCLUDES" "KW_JUMP", "KW_MACRO", "KW_PATTERN", .... }; static char *token_equivs1[] = { .... , "KW_IF" , "KW_IGNOREPAT" , "KW_INCLUDES" "KW_JUMP" , "KW_MACRO" , "KW_PATTERN" .... }; www.viva64.com
  18. 18. “The fault lies with the compiler” It is better to try understanding what is going on before applying workarounds. Ffdshow TprintPrefs::TprintPrefs(....) { memset(this, 0, sizeof(this)); // This doesn't seem to // help after optimization. dx = dy = 0; isOSD = false; xpos = ypos = 0; align = 0; linespacing = 0; sizeDx = 0; sizeDy = 0; ... } www.viva64.com
  19. 19. Constructions protecting from mistakes. CountOf(). This is bad. Shareaza #define countof(array) (sizeof(array) / sizeof((array)[0])) size_t AnsiDecodeChar(..., TCHAR arrChar[2], ....) { .... nCharSize = MultiByteToWideChar(...., arrChar, countof(arrChar)); .... } www.viva64.com
  20. 20. Constructions protecting from mistakes. CountOf(). This one is good. Chromium template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N]; #define arraysize(array) (sizeof(ArraySizeHelper(array))) See more details in “PVS-Studio vs Chromium” article: http://www.viva64.com/en/a/0074/ www.viva64.com
  21. 21. Constructions protecting from mistakes. CountOf(). This one is good. Chromium template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N]; #define arraysize(array) (sizeof(ArraySizeHelper(array))) void Test(int C[3]) { int A[3]; int *B = Foo(); size_t x = arraysize(A); // Ok x = arraysize(B); // Compilation error x = arraysize(C); // Compilation error } www.viva64.com
  22. 22. Constructions protecting from mistakes. Automatic calculation of a size. errno_t _strupr_s(char * _Str, size_t _Size); template <size_t _Size> errno_t _strupr_s(char (&_String)[_Size]); Implementation: template <size_t _Size> inline errno_t _strupr_s(_DstType (&_Dst)[_Size]) { return _strupr_s(_Dst, _Size); } www.viva64.com
  23. 23. Do not be greedy when placing additional parenthesis and lines Wine if ((hr = SafeArrayGetUBound( sa, 1, &size ) != S_OK)) { SafeArrayUnaccessData( sa ); return hr; } MongoDB ss << (sizeof(char *) == 8) ? " 64bit" : " 32bit"; // A beautiful example. // 0 or 1 will be printed instead of "32bit" / "64bit". www.viva64.com
  24. 24. Do not be greedy when placing additional parenthesis and lines Qt bool QConfFileSettingsPrivate::readIniLine(....) { .... char ch; while (i < dataLen && ((ch = data.at(i) != 'n') && ch != 'r')) ++i; .... } www.viva64.com
  25. 25. Use static code analyzer • Example from PVS-Studio: “an error which could not be discovered in 50 hours, was found by a single analyzer launch and fixed in less then an hour!” (Source: http://www.viva64.com/en/b/0221/) • You can discover problems that you had no idea even existed. www.viva64.com
  26. 26. Errors that are not known to even exist: char c = memcmp(). Such an error was a source of a serious vulnerability in MySQL/MariaDB up to verisions 5.1.61, 5.2.11, 5.3.5, 5.5.22. The essence here is that when a user connects to MySQL /MariaDB , a token is generated (SHA from password and hash), which in turn is compared to the expected result of ‘memcmp’ function. On several platforms, the return value can fall from the range of [-128..127]. As a result, in 1 chance in 235, the comparison of hash and the expected value always returns ‘true’, regardless of the hash itself. This leads to situation in which a simple bash command provides root access to a vulnerable MySQL server, even if the password is unknown. typedef char my_bool; ... my_bool check(...) { return memcmp(...); } Details: Security vulnerability in MySQL/MariaD - http://seclists.org/oss-sec/2012/q2/493 www.viva64.com
  27. 27. Errors that are not known to even exist: memset + optimization. Overwriting memory - why? - http://www.viva64.com/en/k/0041/ V597. The compiler could delete the 'memset' function call, which is used to flush 'Foo' buffer. The RtlSecureZeroMemory() function should be used to erase the private data - http://www.viva64.com/en/d/0208/ php char* php_md5_crypt_r(const char *pw,const char *salt, char *out) { static char passwd[MD5_HASH_MAX_LEN], *p; unsigned char final[16]; .... /* Don't leave anything around in vm they could use. */ memset(final, 0, sizeof(final)); return (passwd); } www.viva64.com
  28. 28. Errors that are not known to even exist: strncat. char *strncat( char *strDest, const char *strSource, size_t count ); MSDN: strncat does not check for sufficient space in strDest; it is therefore a potential cause of buffer overruns. Keep in mind that count limits the number of characters appended; it is not a limit on the size of strDest. www.viva64.com
  29. 29. Errors that are not known to even exist: strncat. char newProtoFilter[2048] = "...."; strncat(newProtoFilter, szTemp, 2048); strncat(newProtoFilter, "|", 2048); char filename[NNN]; ... strncat(filename, dcc->file_info.filename, sizeof(filename) - strlen(filename)); www.viva64.com strncat(...., sizeof(filename) - strlen(filename) - 1);
  30. 30. Additional defense. Testing the tests. Chromium: profile_sync_service_password_unittest.cc 261 static bool PasswordFormComparator(const PasswordForm& pf1, const PasswordForm& pf2) { ...... if (pf1.username_value < pf2.username_value) return true; if (pf1.username_value < pf2.username_value) return true; if (pf1.password_element < pf2.password_element) return true; if (pf1.password_value < pf2.password_value) return true; return false; } It is better to be safe than sorry. On method compliments the other. www.viva64.com
  31. 31. Summary: • A developer spends more time reading the code than writing it. • Try writing as clear and simple as possible. • Do not save on parenthesis, commas, spaces and lines. • Format your code. • Use static analysis. • Employ “defensive programming”. • Perform code reviews.
  32. 32. Time for questions. E-Mail: Karpov@viva64.com My twitter: https://twitter.com/Code_Analysis PVS-Studio: http://www.viva64.com/en/pvs-studio/ www.viva64.com