| 1 | // RUN: %check_clang_tidy %s bugprone-suspicious-memory-comparison %t \ |
| 2 | // RUN: -- -- -target x86_64-unknown-unknown -std=c99 |
| 3 | |
| 4 | typedef __SIZE_TYPE__ size_t; |
| 5 | int memcmp(const void *lhs, const void *rhs, size_t count); |
| 6 | |
| 7 | // Examples from cert rule exp42-c |
| 8 | |
| 9 | struct S { |
| 10 | char c; |
| 11 | int i; |
| 12 | char buffer[13]; |
| 13 | }; |
| 14 | |
| 15 | void exp42_c_noncompliant(const struct S *left, const struct S *right) { |
| 16 | if ((left && right) && (0 == memcmp(lhs: left, rhs: right, count: sizeof(struct S)))) { |
| 17 | // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: comparing object representation of type 'struct S' which does not have a unique object representation; consider comparing the members of the object manually |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | void exp42_c_compliant(const struct S *left, const struct S *right) { |
| 22 | if ((left && right) && (left->c == right->c) && (left->i == right->i) && |
| 23 | (0 == memcmp(lhs: left->buffer, rhs: right->buffer, count: 13))) { |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | #pragma pack(push, 1) |
| 28 | struct Packed_S { |
| 29 | char c; |
| 30 | int i; |
| 31 | char buffer[13]; |
| 32 | }; |
| 33 | #pragma pack(pop) |
| 34 | |
| 35 | void compliant_packed(const struct Packed_S *left, |
| 36 | const struct Packed_S *right) { |
| 37 | if ((left && right) && (0 == memcmp(lhs: left, rhs: right, count: sizeof(struct Packed_S)))) { |
| 38 | // no-warning |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | // Examples from cert rule flp37-c |
| 43 | |
| 44 | struct S2 { |
| 45 | int i; |
| 46 | float f; |
| 47 | }; |
| 48 | |
| 49 | int flp37_c_noncompliant(const struct S2 *s1, const struct S2 *s2) { |
| 50 | if (!s1 && !s2) |
| 51 | return 1; |
| 52 | else if (!s1 || !s2) |
| 53 | return 0; |
| 54 | return 0 == memcmp(lhs: s1, rhs: s2, count: sizeof(struct S2)); |
| 55 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: comparing object representation of type 'struct S2' which does not have a unique object representation; consider comparing the members of the object manually |
| 56 | } |
| 57 | |
| 58 | int flp37_c_compliant(const struct S2 *s1, const struct S2 *s2) { |
| 59 | if (!s1 && !s2) |
| 60 | return 1; |
| 61 | else if (!s1 || !s2) |
| 62 | return 0; |
| 63 | return s1->i == s2->i && s1->f == s2->f; |
| 64 | // no-warning |
| 65 | } |
| 66 | |
| 67 | void Test_Float(void) { |
| 68 | float a, b; |
| 69 | memcmp(lhs: &a, rhs: &b, count: sizeof(float)); |
| 70 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually |
| 71 | } |
| 72 | |
| 73 | void TestArray_Float(void) { |
| 74 | float a[3], b[3]; |
| 75 | memcmp(lhs: a, rhs: b, count: sizeof(a)); |
| 76 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'float' which does not have a unique object representation; consider comparing the values manually |
| 77 | } |
| 78 | |
| 79 | struct PredeclaredType; |
| 80 | |
| 81 | void Test_PredeclaredType(const struct PredeclaredType *lhs, |
| 82 | const struct PredeclaredType *rhs) { |
| 83 | memcmp(lhs, rhs, count: 1); // no-warning: predeclared type |
| 84 | } |
| 85 | |
| 86 | struct NoPadding { |
| 87 | int x; |
| 88 | int y; |
| 89 | }; |
| 90 | |
| 91 | void Test_NoPadding(void) { |
| 92 | struct NoPadding a, b; |
| 93 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct NoPadding)); |
| 94 | } |
| 95 | |
| 96 | void TestArray_NoPadding(void) { |
| 97 | struct NoPadding a[3], b[3]; |
| 98 | memcmp(lhs: a, rhs: b, count: 3 * sizeof(struct NoPadding)); |
| 99 | } |
| 100 | |
| 101 | struct TrailingPadding { |
| 102 | int i; |
| 103 | char c; |
| 104 | }; |
| 105 | |
| 106 | void Test_TrailingPadding(void) { |
| 107 | struct TrailingPadding a, b; |
| 108 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct TrailingPadding)); |
| 109 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| 110 | memcmp(lhs: &a, rhs: &b, count: sizeof(int)); // no-warning: not comparing entire object |
| 111 | memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); |
| 112 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| 113 | } |
| 114 | |
| 115 | struct TrailingPadding2 { |
| 116 | int i[2]; |
| 117 | char c; |
| 118 | }; |
| 119 | |
| 120 | void Test_TrailingPadding2(void) { |
| 121 | struct TrailingPadding2 a, b; |
| 122 | memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); // no-warning: not comparing entire object |
| 123 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct TrailingPadding2)); |
| 124 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding2' which does not have a unique object representation; consider comparing the members of the object manually |
| 125 | } |
| 126 | |
| 127 | void Test_UnknownCount(size_t count) { |
| 128 | struct TrailingPadding a, b; |
| 129 | memcmp(lhs: &a, rhs: &b, count); // no-warning: unknown count value |
| 130 | } |
| 131 | |
| 132 | void Test_ExplicitVoidCast(void) { |
| 133 | struct TrailingPadding a, b; |
| 134 | memcmp(lhs: (void *)&a, rhs: (void *)&b, |
| 135 | count: sizeof(struct TrailingPadding)); // no-warning: explicit cast |
| 136 | } |
| 137 | |
| 138 | void TestArray_TrailingPadding(void) { |
| 139 | struct TrailingPadding a[3], b[3]; |
| 140 | memcmp(lhs: a, rhs: b, count: 3 * sizeof(struct TrailingPadding)); |
| 141 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct TrailingPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| 142 | } |
| 143 | |
| 144 | struct InnerPadding { |
| 145 | char c; |
| 146 | int i; |
| 147 | }; |
| 148 | |
| 149 | void Test_InnerPadding(void) { |
| 150 | struct InnerPadding a, b; |
| 151 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct InnerPadding)); |
| 152 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct InnerPadding' which does not have a unique object representation; consider comparing the members of the object manually |
| 153 | } |
| 154 | |
| 155 | struct Bitfield_TrailingPaddingBytes { |
| 156 | int x : 10; |
| 157 | int y : 6; |
| 158 | }; |
| 159 | |
| 160 | void Test_Bitfield_TrailingPaddingBytes(void) { |
| 161 | struct Bitfield_TrailingPaddingBytes a, b; |
| 162 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct S)); |
| 163 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBytes' which does not have a unique object representation; consider comparing the members of the object manually |
| 164 | } |
| 165 | |
| 166 | struct Bitfield_TrailingPaddingBits { |
| 167 | int x : 10; |
| 168 | int y : 20; |
| 169 | }; |
| 170 | |
| 171 | void Test_Bitfield_TrailingPaddingBits(void) { |
| 172 | struct Bitfield_TrailingPaddingBits a, b; |
| 173 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_TrailingPaddingBits)); |
| 174 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_TrailingPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually |
| 175 | } |
| 176 | |
| 177 | struct Bitfield_InnerPaddingBits { |
| 178 | char x : 2; |
| 179 | int : 0; |
| 180 | char y : 8; |
| 181 | }; |
| 182 | |
| 183 | void Test_Bitfield_InnerPaddingBits(void) { |
| 184 | struct Bitfield_InnerPaddingBits a, b; |
| 185 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_InnerPaddingBits)); |
| 186 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct Bitfield_InnerPaddingBits' which does not have a unique object representation; consider comparing the members of the object manually |
| 187 | } |
| 188 | |
| 189 | struct Bitfield_NoPadding { |
| 190 | int i : 10; |
| 191 | int j : 10; |
| 192 | int k : 10; |
| 193 | int l : 2; |
| 194 | }; |
| 195 | _Static_assert(sizeof(struct Bitfield_NoPadding) == sizeof(int), |
| 196 | "Bit-fields should line up perfectly" ); |
| 197 | |
| 198 | void Test_Bitfield_NoPadding(void) { |
| 199 | struct Bitfield_NoPadding a, b; |
| 200 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_NoPadding)); // no-warning |
| 201 | } |
| 202 | |
| 203 | struct Bitfield_TrailingUnnamed { |
| 204 | int i[2]; |
| 205 | int : 0; |
| 206 | }; |
| 207 | |
| 208 | void Bitfield_TrailingUnnamed(void) { |
| 209 | struct Bitfield_TrailingUnnamed a, b; |
| 210 | memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); // no-warning |
| 211 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct Bitfield_TrailingUnnamed)); // no-warning |
| 212 | } |
| 213 | |
| 214 | struct PaddingAfterUnion { |
| 215 | union { |
| 216 | unsigned short a; |
| 217 | short b; |
| 218 | } x; |
| 219 | |
| 220 | int y; |
| 221 | }; |
| 222 | |
| 223 | void Test_PaddingAfterUnion(void) { |
| 224 | struct PaddingAfterUnion a, b; |
| 225 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct PaddingAfterUnion)); |
| 226 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterUnion' which does not have a unique object representation; consider comparing the members of the object manually |
| 227 | } |
| 228 | |
| 229 | struct Union_NoPadding { |
| 230 | union { |
| 231 | int a; |
| 232 | unsigned int b; |
| 233 | } x; |
| 234 | |
| 235 | int y; |
| 236 | }; |
| 237 | |
| 238 | void Test_Union_NoPadding(void) { |
| 239 | struct Union_NoPadding a, b; |
| 240 | memcmp(lhs: &a, rhs: &b, count: 2 * sizeof(int)); |
| 241 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct Union_NoPadding)); |
| 242 | } |
| 243 | |
| 244 | union UnionWithPaddingInNestedStruct { |
| 245 | int i; |
| 246 | |
| 247 | struct { |
| 248 | int i; |
| 249 | char c; |
| 250 | } x; |
| 251 | }; |
| 252 | |
| 253 | void Test_UnionWithPaddingInNestedStruct(void) { |
| 254 | union UnionWithPaddingInNestedStruct a, b; |
| 255 | memcmp(lhs: &a, rhs: &b, count: sizeof(union UnionWithPaddingInNestedStruct)); |
| 256 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'union UnionWithPaddingInNestedStruct' which does not have a unique object representation; consider comparing the members of the object manually |
| 257 | } |
| 258 | |
| 259 | struct PaddingInNested { |
| 260 | struct TrailingPadding x; |
| 261 | char y; |
| 262 | }; |
| 263 | |
| 264 | void Test_PaddingInNested(void) { |
| 265 | struct PaddingInNested a, b; |
| 266 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct PaddingInNested)); |
| 267 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingInNested' which does not have a unique object representation; consider comparing the members of the object manually |
| 268 | } |
| 269 | |
| 270 | struct PaddingAfterNested { |
| 271 | struct { |
| 272 | char a; |
| 273 | char b; |
| 274 | } x; |
| 275 | int y; |
| 276 | }; |
| 277 | |
| 278 | void Test_PaddingAfterNested(void) { |
| 279 | struct PaddingAfterNested a, b; |
| 280 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct PaddingAfterNested)); |
| 281 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct PaddingAfterNested' which does not have a unique object representation; consider comparing the members of the object manually |
| 282 | } |
| 283 | |
| 284 | struct AtomicMember { |
| 285 | _Atomic(int) x; |
| 286 | }; |
| 287 | |
| 288 | void Test_AtomicMember(void) { |
| 289 | // FIXME: this is a false positive as the list of objects with unique object |
| 290 | // representations is incomplete. |
| 291 | struct AtomicMember a, b; |
| 292 | memcmp(lhs: &a, rhs: &b, count: sizeof(struct AtomicMember)); |
| 293 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: comparing object representation of type 'struct AtomicMember' which does not have a unique object representation; consider comparing the members of the object manually |
| 294 | } |
| 295 | |