Publicité
Publicité

Contenu connexe

Publicité

Plus de Andrey Karpov(20)

Publicité

C++ Code as Seen by a Hypercritical Reviewer

  1. C++ Code as Seen by a Hypercritical Reviewer Phillip Khandeliants khandeliants@viva64.com
  2. About Me  A lead C++/C# developer at PVS- Studio.  I’ve been developing the C++ analyzer’s core for 3 years.  I educate on modern C++. 2 Текст слайда
  3. What are you talking about? 3
  4. What are you talking about? 4  We all do code reviews
  5. What are you talking about? 5  We all do code reviews  Who doesn't admit this – does it twice as often
  6. What are you talking about? 6  We all do code reviews  Who doesn't admit this – does it twice as often  C++ code reviewers look like a sapper
  7. What are you talking about? 7  We all do code reviews  Who doesn't admit this – does it twice as often  C++ code reviewers look like a sapper  ... except that they can make a mistake more than once 
  8.  We all do code reviews  Who doesn't admit this – does it twice as often  C++ code reviewers look like a sapper  ... except that they can make a mistake more than once   But sometimes the consequences are painful  What are you talking about? 8
  9. Brave code review world 9
  10. 1. 'Auto'matic coding 10
  11. void foo(const std::vector<....> &vec) { .... for (auto i = 0; i < vec.size(); ++i) { // do some magic with vec[i] .... } .... } 11
  12. void foo(const std::vector<....> &vec) { .... for (int i = 0; i < vec.size(); ++i) // 64-bit problems :) { // do some magic with vec[i] .... } .... } 12
  13. void foo(const std::vector<....> &vec) { .... for (size_t i = 0; i < vec.size(); ++i) // ok { // do some magic with vec[i] .... } .... } 13
  14. void foo(const std::vector<....> &vec) { .... for (std::vector<....>::size_type i = 0; i < vec.size(); ++i) { // do some magic with vec[i] .... } .... } 14
  15. void foo(const std::vector<....> &vec) { .... for (auto i = 0uLL; i < vec.size(); ++i) // don't do that on // 128-bit processors { // do some magic with vec[i] .... } .... } 15
  16. void foo(const std::vector<....> &vec) { .... for (auto i = 0uLLL; i < vec.size(); ++i) // ok since C++7d { // do some magic with vec[i] .... } .... } 16
  17. void foo(const std::vector<....> &vec) { .... for (auto i = 0uLLL; i < vec.size(); ++i) // ok since C++7d { // do some magic with vec[i] .... } .... } 17
  18. 2. Reference! I said reference! Perfection! 18
  19. 19 template <typename T> int ColumnDecimal<T>::compareAt(size_t n, size_t m, const IColumn & rhs_, int) const { auto other = static_cast<const Self &>(rhs_); const T &a = data[n]; const T &b = other.data[m]; return decimalLess<T>(b, a, other.scale, scale) ? 1 : (decimalLess<T>(a, b, scale, other.scale) ? -1 : 0); }
  20. 20 template <typename T> int ColumnDecimal<T>::compareAt(size_t n, size_t m, const IColumn & rhs_, int) const { auto other = static_cast<const Self &>(rhs_); const T &a = data[n]; const T &b = other.data[m]; return decimalLess<T>(b, a, other.scale, scale) ? 1 : (decimalLess<T>(a, b, scale, other.scale) ? -1 : 0); }
  21. 21 template <typename T> int ColumnDecimal<T>::compareAt(size_t n, size_t m, const IColumn & rhs_, int) const { auto &other = static_cast<const Self &>(rhs_); const T &a = data[n]; const T &b = other.data[m]; return decimalLess<T>(b, a, other.scale, scale) ? 1 : (decimalLess<T>(a, b, scale, other.scale) ? -1 : 0); }
  22. 22 template <typename T> int ColumnDecimal<T>::compareAt(size_t n, size_t m, const IColumn & rhs_, int) const { decltype(auto) other = static_cast<const Self &>(rhs_); const T &a = data[n]; const T &b = other.data[m]; return decimalLess<T>(b, a, other.scale, scale) ? 1 : (decimalLess<T>(a, b, scale, other.scale) ? -1 : 0); }
  23. 3. Vector-vector, *pChar++ 23
  24. void vector32_inc(std::vector<uint32_t> &v) { for (size_t i = 0; i < v.size(); i++) { v[i]++; } } 24
  25. void vector32_inc(std::vector<uint32_t> &v) { for (size_t i = 0; i < v.size(); i++) { v[i]++; } } void vector8_inc(std::vector<uint8_t> &v) { for (size_t i = 0; i < v.size(); i++) { v[i]++; } } 25
  26. Let's benchmark :) 26 Compiler Element -O1 -O2 -O3 gcc 8 uint8_t 2.0 2.0 2.0 gcc 8 uint32_t 2.3 1.3 0.2 clang 8 uint8_t 9.2 2.0 2.0 clang 8 uint32_t 9.2 0.2 0.2
  27. 27 vector8_inc(std::vector<uint8_t> &): mov rdx, QWORD PTR [rdi] ; it = begin() cmp rdx, QWORD PTR [rdi+8] ; if (it == end()) je .L1 ; return xor eax, eax ; i = 0 .L3: ; do { add BYTE PTR [rdx+rax], 1 ; ++(*(it + i)) mov rdx, QWORD PTR [rdi] ; it = begin() add rax, 1 ; ++i mov rcx, QWORD PTR [rdi+8] ; end = end() sub rcx, rdx ; end = end - it cmp rax, rcx jb .L3 ; } while (i < end) .L1: ret vector32_inc(std::vector<uint32_t> &): mov rax, QWORD PTR [rdi] ; it = begin() mov rdx, QWORD PTR [rdi+8] ; end = end() sub rdx, rax ; end = end - it mov rcx, rdx ; size in bytes shr rcx, 2 ; size in elements je .L1 ; if (size == 0) ; return add rdx, rax ; end = end + it .L3: ; do { add DWORD PTR [rax], 1 ; ++(*it) add rax, 4 ; ++it cmp rax, rdx jne .L3 ; } while (it != end) .L1: ret
  28. 28 vector8_inc(std::vector<uint8_t> &): mov rdx, QWORD PTR [rdi] ; it = begin() cmp rdx, QWORD PTR [rdi+8] ; if (it == end()) je .L1 ; return xor eax, eax ; i = 0 .L3: ; do { add BYTE PTR [rdx+rax], 1 ; ++(*(it + i)) mov rdx, QWORD PTR [rdi] ; it = begin() add rax, 1 ; ++i mov rcx, QWORD PTR [rdi+8] ; end = end() sub rcx, rdx ; end = end - it cmp rax, rcx jb .L3 ; } while (i < end) .L1: ret vector32_inc(std::vector<uint32_t> &): mov rax, QWORD PTR [rdi] ; it = begin() mov rdx, QWORD PTR [rdi+8] ; end = end() sub rdx, rax ; end = end - it mov rcx, rdx ; size in bytes shr rcx, 2 ; size in elements je .L1 ; if (size == 0) ; return add rdx, rax ; end = end + it .L3: ; do { add DWORD PTR [rax], 1 ; ++(*it) add rax, 4 ; ++it cmp rax, rdx jne .L3 ; } while (it != end) .L1: ret
  29. void vector8_inc(std::vector<uint8_t> &v) { for (size_t i = 0; i < v.size(); i++) { v[i]++; } } 29
  30. void vector8_inc(std::vector<uint8_t> &v) { for (size_t i = 0; i < v.size(); i++) { v[i]++; } } void vector8_inc(std::vector<uint8_t> &v) { auto it = v.begin(); const auto end = v.end(); for (; it != end; ++it) { ++(*it); } } 30
  31. 31 vector8_inc(std::vector<uint8_t> &): mov rax, QWORD PTR [rdi] ; it = begin() mov rdx, QWORD PTR [rdi+8] ; end = end() cmp rax, rdx ; if (it == end) je .L1 ; return .L3: ; do { add BYTE PTR [rax], 1 ; ++(*it) add rax, 1 ; ++it cmp rax, rdx ; } while (it != end) .L1: ret
  32. 32 vector8_inc(std::vector<uint8_t> &): mov rax, QWORD PTR [rdi] ; it = begin() mov rdx, QWORD PTR [rdi+8] ; end = end() cmp rax, rdx ; if (it == end) je .L1 ; return .L3: ; do { add BYTE PTR [rax], 1 ; ++(*it) add rax, 1 ; ++it cmp rax, rdx ; } while (it != end) .L1: ret
  33. Let's make benchmarks great again! Compiler uint8_t -O1 -O2 -O3 gcc 8 (before) 2.0 2.0 2.0 gcc 8 (after) 1.3 1.3 0.06 gcc speedup 1.5x 1.5x 33.4x Compiler uint8_t -O1 -O2 -O3 clang 8 (before) 9.2 2.0 2.0 clang 8 (after) 20.3 0.06 0.06 clang speedup 0.45x 33.4x 33.4x
  34. void vector8_inc(std::vector<uint8_t> &v) { auto it = v.begin(); const auto end = v.end(); for (; it != end; ++it) { ++(*it); } } 34
  35. void vector8_inc(std::vector<uint8_t> &v) { auto it = v.begin(); const auto end = v.end(); for (; it != end; ++it) { ++(*it); } } void vector8_inc(std::vector<uint8_t> &v) { for (auto &elem : v) { ++elem; } } 35
  36. 36
  37. 4. Security? Security! 37
  38. #include <cstring> #include <memory> void InputPassword(char *pswd); void ProcessPassword(const char *pswd); #define MAX_PASSWORD_LEN .... void Foo() { char password[MAX_PASSWORD_LEN]; InputPassword(password); ProcessPassword(password); memset(password, 0, sizeof(password)); } 38
  39. #include <cstring> #include <memory> void InputPassword(char *pswd); void ProcessPassword(const char *pswd); #define MAX_PASSWORD_LEN .... void Foo() { char password[MAX_PASSWORD_LEN]; InputPassword(password); ProcessPassword(password); memset(password, 0, sizeof(password)); } 39
  40. 40
  41. #include <cstring> #include <memory> void InputPassword(char *pswd); void ProcessPassword(const char *pswd); #define MAX_PASSWORD_LEN .... void Foo() { char *password = new char[MAX_PASSWORD_LEN]; InputPassword(password); ProcessPassword(password); memset(password, 0, MAX_PASSWORD_LEN); delete[] password; } 41
  42. 42
  43. void tds_answer_challenge(....) { #define MAX_PW_SZ 14 .... if (ntlm_v == 1) { .... /* with security is best be pedantic */ memset(hash, 0, sizeof(hash)); memset(passwd_buf, 0, sizeof(passwd_buf)); memset(ntlm2_challenge, 0, sizeof(ntlm2_challenge)); } else { .... } } 43
  44. typedef struct tds_answer { unsigned char lm_resp[24]; unsigned char nt_resp[24]; } TDSANSWER; static TDSRET tds7_send_auth(....) { size_t current_pos; TDSANSWER answer; .... /* for security reason clear structure */ memset(&answer, 0, sizeof(TDSANSWER)); return tds_flush_packet(tds); } 44
  45. char* crypt_md5(const char* pw, const char* salt) { unsigned char final[MD5_SIZE]; .... /* Don't leave anything around in vm they could use. */ memset(final, 0, sizeof final); return passwd; } 45
  46. void MD4Engine::transform (UInt32 state[4], const unsigned char block[64]) { UInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; decode(x, block, 64); .... /* Zeroize sensitive information. */ std::memset(x, 0, sizeof(x)); } 46
  47. char* px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen) { .... unsigned char final[MD5_SIZE]; .... /* Don't leave anything around in vm they could use. */ memset(final, 0, sizeof final); .... } 47
  48. 48
  49.  Custom safe_memset + disabled LTO/WPO  Access a non-volatile object through a volatile pointer  Call memset through a volatile function pointer  Volatile assembly code  Memset + memory barrier  Disable compiler optimizations (-fno-builtin-memset)  C11: memset_s  Windows: RtlSecureZeroMemory  FreeBSD & OpenBSD: explicit_bzero  Linux Kernel: memzero_explicit Ways to fix 49
  50. 5. Dirty thoughts data 50
  51. static const char* basic_gets(int *cnt) { .... int c = getchar(); if (c < 0) { if ( fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) { break; } /* remove endline */ command_buf[strlen(command_buf)-1] = '0'; break; } .... } 51
  52. static const char* basic_gets(int *cnt) { .... int c = getchar(); if (c < 0) { if ( fgets(command_buf, sizeof(command_buf) - 1, stdin) != command_buf) { break; } /* remove endline */ command_buf[strlen(command_buf)-1] = '0'; break; } .... } 52
  53. int main (int argc, char *argv[]) { .... else if (fgets(readbuf, BUFSIZ, stdin) == NULL) { if (feof (stdin)) break; error (EXIT_FAILURE, errno, _("input error")); } if (readbuf[strlen(readbuf) - 1] == 'n') readbuf[strlen(readbuf) - 1] = '0'; .... } 53
  54. int main (int argc, char *argv[]) { .... else if (fgets(readbuf, BUFSIZ, stdin) == NULL) { if (feof (stdin)) break; error (EXIT_FAILURE, errno, _("input error")); } if (readbuf[strlen(readbuf) - 1] == 'n') readbuf[strlen(readbuf) - 1] = '0'; .... } 54 CVE-2015-8948
  55. int main (int argc, char *argv[]) { .... else if (getline(&line, &linelen, stdin) == -1) { if (feof (stdin)) break; error (EXIT_FAILURE, errno, _("input error")); } if (line[strlen(line) - 1] == 'n') line[strlen(line) - 1] = '0'; .... } 55
  56. int main (int argc, char *argv[]) { .... else if (getline(&line, &linelen, stdin) == -1) { if (feof (stdin)) break; error (EXIT_FAILURE, errno, _("input error")); } if (line[strlen(line) - 1] == 'n') line[strlen(line) - 1] = '0'; .... } 56 CVE-2016-6262
  57. 6. Last-ditch effort 57
  58. inline void Init( float ix=0, float iy=0, float iz=0, float iw = 0 ) { SetX( ix ); SetY( iy ); SetZ( iz ); SetZ( iw ); } 58
  59. inline void Init( float ix=0, float iy=0, float iz=0, float iw = 0 ) { SetX( ix ); SetY( iy ); SetZ( iz ); SetZ( iw ); } 59
  60. 60 inline void Init( float ix=0, float iy=0, float iz=0, float iw = 0 ) { SetX( ix ); SetY( iy ); SetZ( iz ); SetW( iw ); }
  61. 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; 61
  62. 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; 62
  63. if (protocol.EqualsIgnoreCase("http") || protocol.EqualsIgnoreCase("https") || protocol.EqualsIgnoreCase("news") || protocol.EqualsIgnoreCase("ftp") || protocol.EqualsIgnoreCase("file") || protocol.EqualsIgnoreCase("javascript") || protocol.EqualsIgnoreCase("ftp")) { 63
  64. if (protocol.EqualsIgnoreCase("http") || protocol.EqualsIgnoreCase("https") || protocol.EqualsIgnoreCase("news") || protocol.EqualsIgnoreCase("ftp") || protocol.EqualsIgnoreCase("file") || protocol.EqualsIgnoreCase("javascript") || protocol.EqualsIgnoreCase("ftp")) { 64
  65. 7. Zero, one, two, Freddy's coming for you! 65
  66. Sequence< OUString > FirebirdDriver:: getSupportedServiceNames_Static() throw (RuntimeException) { Sequence< OUString > aSNS( 2 ); aSNS[0] = "com.sun.star.sdbc.Driver"; aSNS[0] = "com.sun.star.sdbcx.Driver"; return aSNS; } 66
  67. Sequence< OUString > FirebirdDriver:: getSupportedServiceNames_Static() throw (RuntimeException) { Sequence< OUString > aSNS( 2 ); aSNS[0] = "com.sun.star.sdbc.Driver"; aSNS[0] = "com.sun.star.sdbcx.Driver"; return aSNS; } 67
  68. struct short2 { short values[2]; short2(short s1, short s2) { values[0] = s1; values[2] = s2; } .... }; 68
  69. struct short2 { short values[2]; short2(short s1, short s2) { values[0] = s1; values[2] = s2; } .... }; 69
  70. 8. Evil within Comparisons! 70
  71. string _server; .... bool operator<( const ServerAndQuery& other ) const { if ( ! _orderObject.isEmpty() ) return _orderObject.woCompare( other._orderObject ) < 0; if ( _server < other._server ) return true; if ( other._server > _server ) return false; return _extra.woCompare( other._extra ) < 0; } Pattern: A < B, B > A 71
  72. string _server; .... bool operator<( const ServerAndQuery& other ) const { if ( ! _orderObject.isEmpty() ) return _orderObject.woCompare( other._orderObject ) < 0; if ( _server < other._server ) return true; if ( other._server > _server ) return false; return _extra.woCompare( other._extra ) < 0; } Pattern: A < B, B > A 72
  73. bool operator==(const SComputePipelineStateDescription &other) const { return 0 == memcmp(this, &other, sizeof(this)); } Pattern: Evaluating the Size of a Pointer Instead of the Size of the Structure/Class 73
  74. bool operator==(const SComputePipelineStateDescription &other) const { return 0 == memcmp(this, &other, sizeof(this)); } Pattern: Evaluating the Size of a Pointer Instead of the Size of the Structure/Class 74
  75. SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2) { .... SSHORT cmp = memcmp(str1, str2, MIN(len1, len2)); if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); return cmp; } Pattern: Incorrect Use of the memcmp result 75
  76. SSHORT TextType::compare(ULONG len1, const UCHAR* str1, ULONG len2, const UCHAR* str2) { .... SSHORT cmp = memcmp(str1, str2, MIN(len1, len2)); if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); return cmp; } Pattern: Incorrect Use of the memcmp result 76
  77. if (cmp == 0) cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0)); Pattern: Incorrect Use of the memcmp result 77
  78. bool Peptide::operator==(Peptide& p) { .... for (i = 0, j = 0; i < this->stripped.length(), j < p.stripped.length(); i++, j++) { .... } Pattern: Incorrect Loops 78
  79. bool Peptide::operator==(Peptide& p) { .... for (i = 0, j = 0; i < this->stripped.length(), j < p.stripped.length(); i++, j++) { .... } Pattern: Incorrect Loops 79
  80. bool equals( class1* val1, class2* val2 ) const { ... size_t size = val1->size(); ... while ( --size >= 0 ) { if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } ... } Pattern: Incorrect Loops 80
  81. bool equals( class1* val1, class2* val2 ) const { ... size_t size = val1->size(); ... while ( --size >= 0 ) { if ( !comp(*itr1,*itr2) ) return false; itr1++; itr2++; } ... } Pattern: Incorrect Loops 81
  82. 9. Use <=>, Luke! 82
  83. Base equality comparison 83 struct Foo { int a, b; };
  84. Base equality comparison 84 struct Foo { int a, b; }; bool operator==(Foo lhs, Foo rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; }
  85. Base equality comparison 85 struct Foo { int a, b; }; bool operator==(Foo lhs, Foo rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } bool operator!=(Foo lhs, Foo rhs) { return !(lhs == rhs); }
  86. Base 'less' comparison 86 struct Foo { int a, b; }; bool operator<(Foo lhs, Foo rhs) { return lhs.a < rhs.a && lhs.b < rhs.b; }
  87. Base 'less' comparison 87 struct Foo { int a, b; }; bool operator<(Foo lhs, Foo rhs) { return lhs.a < rhs.a && lhs.b < rhs.b; } Foo { 1, 2 } < Foo { 2, 1 }; // <= false Foo { 2, 1 } < Foo { 1, 2 }; // <= false
  88. Base 'less' comparison 88 struct Foo { int a, b; }; bool operator<(Foo lhs, Foo rhs) { if (lhs.a < rhs.a) return true; if (rhs.a < lhs.a) return false; return lhs.b < rhs.b; } Foo { 1, 2 } < Foo { 2, 1 }; // <= true Foo { 2, 1 } < Foo { 1, 2 }; // <= false
  89. Base 'less' comparison 89 struct Foo { double a; }; bool operator<(Foo lhs, Foo rhs) { return lhs.a < rhs.a; }
  90. Base 'less' comparison 90 struct Foo { double a; }; bool operator<(Foo lhs, Foo rhs) { return lhs.a < rhs.a; } bool operator>=(Foo lhs, Foo rhs) { return !(lhs < rhs); }
  91. Base 'less' comparison 91 struct Foo { double a; }; bool operator<(Foo lhs, Foo rhs) { return lhs.a < rhs.a; } bool operator>=(Foo lhs, Foo rhs) { return !(lhs < rhs); } Foo { 1.0 } < Foo { 2.0 }; // <= true Foo { 1.0 } < Foo { NaN }; // <= false Foo { 1.0 } >= Foo { NaN }; // <= true
  92. Comparisons in C++20 92 #include <compare> struct Foo { double a; auto operator<=>(const Foo &rhs) const = default; }; Foo { 1.0 } < Foo { 2.0 }; // <= true Foo { 1.0 } < Foo { NaN }; // <= false Foo { 1.0 } >= Foo { NaN }; // <= false
  93. 10. Payne, I can't feel my legs pointer 93
  94. void Item_Paint(itemDef_t *item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return; } .... } 94
  95. void Item_Paint(itemDef_t *item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return; } .... } 95
  96. void Item_Paint(std::unique_ptr<itemDef_t> &item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return; } .... } 96
  97. void Item_Paint(std::shared_ptr<itemDef_t> &item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (item == NULL) { return; } .... } 97
  98. void Item_Paint(std::optional<itemDef_t> &item) { vec4_t red; menuDef_t *parent = (menuDef_t*)item->parent; red[0] = red[3] = 1; red[1] = red[2] = 0; if (!item) { return; } .... } 98
  99. static struct DerivedMesh *dynamicPaint_Modifier_apply(....) { .... for (; surface; surface = surface->next) { PaintSurfaceData *sData = surface->data; if (surface && surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) { .... } 99
  100. static struct DerivedMesh *dynamicPaint_Modifier_apply(....) { .... for (; surface; surface = surface->next) { PaintSurfaceData *sData = surface->data; if (surface && surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ && sData) { .... } 100
  101. 11. Push me and then emplace me! 101
  102. struct G584_Info { G584_Info(const Ptree *p, bool add, bool mul, bool sub, bool div) { .... } .... const Ptree *m_p; bool m_add; bool m_mul; bool m_sub; bool m_div; }; 102
  103. static void G584_CollectExprInfo(const Ptree *p, vector<G584_Info> &infs) { .... auto what = p->What(); if (what == ntParenExpr) { // Remember the expression in parentheses and continue infs.push_back(G584_Info(p, true, true, false, false)); p = SafeSkipParentesis(p); } .... } 103
  104. static void G584_CollectExprInfo(const Ptree *p, vector<G584_Info> &infs) { .... auto what = p->What(); if (what == ntParenExpr) { // Remember the expression in parentheses and continue infs.push_back(G584_Info(p, true, true, false, false)); p = SafeSkipParentesis(p); } .... } 104
  105. static void G584_CollectExprInfo(const Ptree *p, vector<G584_Info> &infs) { .... auto what = p->What(); if (what == ntParenExpr) { // Remember the expression in parentheses and continue infs.emplace_back(p, true, true, false, false); p = SafeSkipParentesis(p); } .... } 105
  106. struct G584_Info { G584_Info(const Ptree *p, bool add, bool mul, bool sub, bool div) { .... } .... const Ptree *m_p; bool m_add; bool m_mul; bool m_sub; bool m_div; }; 106
  107. struct G584_Info { G584_Info(const Ptree *p, bool add, bool mul, bool sub, bool div) { .... } .... const Ptree *m_p; bool m_add; bool m_mul; bool m_sub; bool m_div; }; 107
  108. static void G584_CollectExprInfo(const Ptree *p, vector<G584_Info> &infs) { .... auto what = p->What(); if (what == ntParenExpr) { // Remember the expression in parentheses and continue infs.emplace_back(p, true, true, false, false); // ok since C++20 p = SafeSkipParentesis(p); } .... } 108
  109. 109
  110. 12. I will find you and insert you! 110
  111. void AddFunctionDangerousInfo(const vstring &strFunctionInfo, const FunctionDangerousInfo &info) { FunctionDangerousInfoMap &infoMap = GetFunctionDangerousInfoMap(); DangerousInfoIterator it = infoMap.find(strFunctionInfo); if (it == infoMap.end()) { infoMap.insert(make_pair(strFunctionInfo, dangerousInfo)); } else { FunctionDangerousInfo &a = it->second; // some works with 'a' } } 111
  112. void AddFunctionDangerousInfo(const vstring &strFunctionInfo, const FunctionDangerousInfo &info) { FunctionDangerousInfoMap &infoMap = GetFunctionDangerousInfoMap(); DangerousInfoIterator it = infoMap.find(strFunctionInfo); if (it == infoMap.end()) { infoMap.insert(make_pair(strFunctionInfo, dangerousInfo)); } else { FunctionDangerousInfo &a = it->second; // some works with 'a' } } 112
  113. void AddFunctionDangerousInfo(....) { auto &infoMap = GetFunctionDangerousInfoMap(); if (auto it = infoMap.find(strFunctionInfo); it == infoMap.end()) { infoMap.emplace(strFunctionInfo, dangerousInfo); } else { FunctionDangerousInfo &a = it->second; // some works with 'a' } } 113
  114. void AddFunctionDangerousInfo(....) { auto &infoMap = GetFunctionDangerousInfoMap(); if (auto it = infoMap.find(strFunctionInfo); it == infoMap.end()) { infoMap.emplace(strFunctionInfo, dangerousInfo); } else { FunctionDangerousInfo &a = it->second; // some works with 'a' } } 114
  115. void AddFunctionDangerousInfo(....) { auto &infoMap = GetFunctionDangerousInfoMap(); if (auto it = infoMap.lower_bound(strFunctionInfo); it != infoMap.end()) { auto &a = it->second; // some works with 'a' } else { infoMap.emplace_hint(it, strFunctionInfo, dangerousInfo); } } 115
  116. void AddFunctionDangerousInfo(....) { auto &infoMap = GetFunctionDangerousInfoMap(); if (auto it = infoMap.lower_bound(strFunctionInfo); it != infoMap.end() && it->first == strFunctionInfo) { auto &a = it->second; // some works with 'a' } else { infoMap.emplace_hint(it, strFunctionInfo, dangerousInfo); } } 116
  117. 13. Is it alive? 117
  118. struct Foo { int i; double d; }; Foo* bar() { Foo *ptr = (Foo *) malloc(sizeof(Foo)); if (ptr == NULL) return NULL; ptr->i = 0; ptr->d = 0.0; return ptr; } 118
  119. struct Foo { int i; double d; }; Foo* bar() { Foo *ptr = (Foo *) malloc(sizeof(Foo)); if (ptr == NULL) return NULL; ptr->i = 0; // ok in C, UB in C++ ptr->d = 0.0; // ok in C, UB in C++ return ptr; } 119
  120. struct Foo { int i; double d; }; Foo* bar() { Foo *ptr = (Foo *) malloc(sizeof(Foo)); if (ptr == NULL) return NULL; new (ptr) Foo; ptr->i = 0; // ok in C++ ptr->d = 0.0; // ok in C++ return ptr; } 120
  121. struct Foo { int i; double d; }; Foo* bar() { Foo *ptr = (Foo *) malloc(sizeof(Foo)); if (ptr == NULL) return NULL; ptr->i = 0; // ok in C, UB in C++ until C++20 ptr->d = 0.0; // ok in C, UB in C++ until C++20 return ptr; } 121
  122. 14. Mind the sign 122
  123. int foo(const char *s) { int r = 0; while (*s) { r += ((r * 20891 + *s * 200) | *s ^ 4 | *s ^ 3 ) ^ (r >> 1); s++; } return r & 0x7fffffff; } 124
  124. int foo(const char *s) { int r = 0; while (*s) { r += ((r * 20891 + *s * 200) | *s ^ 4 | *s ^ 3 ) ^ (r >> 1); s++; } return r & 0x7fffffff; } gcc-8 -O2 -std=c++17 -funsigned-char source.cpp 125
  125. int foo(const char *s) { int r = 0; while (*s) { r += ((r * 20891 + *s * 200) | *s ^ 4 | *s ^ 3 ) ^ (r >> 1); s++; } return r & 0x7fffffff; } gcc-8 -O2 -std=c++17 -funsigned-char source.cpp 126
  126. 15. No exceptions, except... 129
  127. BOOL WINAPI DllMain(HANDLE hModule, ULONG nReason, LPVOID /*pSituation*/) { BOOL br = TRUE; if (nReason == DLL_PROCESS_ATTACH) { // Remember our hModule. g_hModule = hModule; g_hInstance = (HINSTANCE)g_hModule; // Make sure we're properly registered. if (FAILED(DllRegisterServer())) br = FALSE; } else if (nReason == DLL_PROCESS_DETACH) { // Nothing to do. } return br; } 130
  128. BOOL WINAPI DllMain(HANDLE hModule, ULONG nReason, LPVOID /*pSituation*/) { BOOL br = TRUE; if (nReason == DLL_PROCESS_ATTACH) { // Remember our hModule. g_hModule = hModule; g_hInstance = (HINSTANCE)g_hModule; // Make sure we're properly registered. if (FAILED(DllRegisterServer())) br = FALSE; } else if (nReason == DLL_PROCESS_DETACH) { // Nothing to do. } return br; } 131
  129. HRESULT WINAPI DllRegisterServer(VOID) { .... hr = ::RegOpenKeyEx(HKEY_CURRENT_USER, "SoftwaregeOgeOShellPlugins", NULL, KEY_WRITE, &hk); if ( SUCCEEDED(hr = HRESULT_FROM_WIN32(hr)) ) { strcpy(szValue, "geOCommandTime.dll,0"); DllGetObjectInfo(0, GI_Name, szName, MAX_PATH); hr = ::RegSetValueEx(hk, szName, 0, REG_SZ, (LPBYTE)szValue, strlen(szValue)); hr = HRESULT_FROM_WIN32(hr); RegCloseKey(hk); } .... return hr; } 132
  130. HRESULT WINAPI DllGetObjectInfo(DWORD dwPluginId, DWORD dwInfo, VOID *pBuffer, DWORD dwBuffer) { .... // Get the specified plugin: hr = DllGetObject(dwPluginId, &pPlugin); if (SUCCEEDED(hr)) { // We got it, so get some info: hr = pPlugin->GetInfo(dwInfo, pBuffer, dwBuffer); // And delete the plugin: delete pPlugin; } .... return hr; } 133
  131. HRESULT WINAPI DllGetObjectInfo(DWORD dwPluginId, DWORD dwInfo, VOID *pBuffer, DWORD dwBuffer) { .... // Get the specified plugin: hr = DllGetObject(dwPluginId, &pPlugin); if (SUCCEEDED(hr)) { // We got it, so get some info: hr = pPlugin->GetInfo(dwInfo, pBuffer, dwBuffer); // And delete the plugin: delete pPlugin; } .... return hr; } 134
  132. HRESULT WINAPI DllGetObject(DWORD dwPluginId, IShellPlugin **ppPlugin) { .... { // We need to create a new command plugin: switch (dwPluginId) { case 0: *ppPlugin = new CCommandPlugin; break; default: *ppPlugin = NULL; }; .... } .... return hr; } 135
  133. HRESULT WINAPI DllGetObject(DWORD dwPluginId, IShellPlugin **ppPlugin) { .... { // We need to create a new command plugin: switch (dwPluginId) { case 0: *ppPlugin = new CCommandPlugin; break; default: *ppPlugin = NULL; }; .... } .... return hr; } 136
  134. 10 commandments 137
  135.  Thou shalt not auto, unless thy faith is strong and pure 138
  136.  Thou shalt not auto, unless thy faith is strong and pure  Thou shalt not write indexed loops for they are abominations before the Code 139
  137.  Thou shalt not auto, unless thy faith is strong and pure  Thou shalt not write indexed loops for they are abominations before the Code  Thou shalt wash thy data thoroughly before releasing it 140
  138.  Thou shalt not auto, unless thy faith is strong and pure  Thou shalt not write indexed loops for they are abominations before the Code  Thou shalt wash thy data thoroughly before releasing it  Thou shalt not accept data from strangers for they might be sinful 141
  139.  Thou shalt not auto, unless thy faith is strong and pure  Thou shalt not write indexed loops for they are abominations before the Code  Thou shalt wash thy data thoroughly before releasing it  Thou shalt not accept data from strangers for they might be sinful  Thou shalt not copy-paste thy code blocks 142
  140.  Thy comparison routines shall be correct or else the Wrath of Code will get thee 143
  141.  Thy comparison routines shall be correct or else the Wrath of Code will get thee  Thou shalt check thy nullables for they are sinful 144
  142.  Thy comparison routines shall be correct or else the Wrath of Code will get thee  Thou shalt check thy nullables for they are sinful  Thou shalt not push that which can be emplaced 145
  143.  Thy comparison routines shall be correct or else the Wrath of Code will get thee  Thou shalt check thy nullables for they are sinful  Thou shalt not push that which can be emplaced  Thou shalt not cook signed values with overflow semantics 146
  144.  Thy comparison routines shall be correct or else the Wrath of Code will get thee  Thou shalt check thy nullables for they are sinful  Thou shalt not push that which can be emplaced  Thou shalt not cook signed values with overflow semantics  He who is without noexcept shall throw, and none other 147
  145. END Q&A148
Publicité