-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Diagnose taking address and reference binding of packed members
This patch implements PR#22821. Taking the address of a packed member is dangerous since the reduced alignment of the pointee is lost. This can lead to memory alignment faults in some architectures if the pointer value is dereferenced. This change adds a new warning to clang emitted when taking the address of a packed member. A packed member is either a field/data member declared as attribute((packed)) or belonging to a struct/class declared as such. The associated flag is -Waddress-of-packed-member. Conversions (either implicit or via a valid casting) to pointer types with lower or equal alignment requirements (e.g. void* or char*) silence the warning. This change also adds a new error diagnostic when the user attempts to bind a reference to a packed member, regardless of the alignment. Differential Revision: https://reviews.llvm.org/D20561 llvm-svn: 275417
- llvmorg-21-init
- llvmorg-20.1.0-rc2
- llvmorg-20.1.0-rc1
- llvmorg-20-init
- llvmorg-19.1.7
- llvmorg-19.1.6
- llvmorg-19.1.5
- llvmorg-19.1.4
- llvmorg-19.1.3
- llvmorg-19.1.2
- llvmorg-19.1.1
- llvmorg-19.1.0
- llvmorg-19.1.0-rc4
- llvmorg-19.1.0-rc3
- llvmorg-19.1.0-rc2
- llvmorg-19.1.0-rc1
- llvmorg-19-init
- llvmorg-18.1.8
- llvmorg-18.1.7
- llvmorg-18.1.6
- llvmorg-18.1.5
- llvmorg-18.1.4
- llvmorg-18.1.3
- llvmorg-18.1.2
- llvmorg-18.1.1
- llvmorg-18.1.0
- llvmorg-18.1.0-rc4
- llvmorg-18.1.0-rc3
- llvmorg-18.1.0-rc2
- llvmorg-18.1.0-rc1
- llvmorg-18-init
- llvmorg-17.0.6
- llvmorg-17.0.5
- llvmorg-17.0.4
- llvmorg-17.0.3
- llvmorg-17.0.2
- llvmorg-17.0.1
- llvmorg-17.0.0
- llvmorg-17.0.0-rc4
- llvmorg-17.0.0-rc3
- llvmorg-17.0.0-rc2
- llvmorg-17.0.0-rc1
- llvmorg-17-init
- llvmorg-16.0.6
- llvmorg-16.0.5
- llvmorg-16.0.4
- llvmorg-16.0.3
- llvmorg-16.0.2
- llvmorg-16.0.1
- llvmorg-16.0.0
- llvmorg-16.0.0-rc4
- llvmorg-16.0.0-rc3
- llvmorg-16.0.0-rc2
- llvmorg-16.0.0-rc1
- llvmorg-16-init
- llvmorg-15.0.7
- llvmorg-15.0.6
- llvmorg-15.0.5
- llvmorg-15.0.4
- llvmorg-15.0.3
- llvmorg-15.0.2
- llvmorg-15.0.1
- llvmorg-15.0.0
- llvmorg-15.0.0-rc3
- llvmorg-15.0.0-rc2
- llvmorg-15.0.0-rc1
- llvmorg-15-init
- llvmorg-14.0.6
- llvmorg-14.0.5
- llvmorg-14.0.4
- llvmorg-14.0.3
- llvmorg-14.0.2
- llvmorg-14.0.1
- llvmorg-14.0.0
- llvmorg-14.0.0-rc4
- llvmorg-14.0.0-rc3
- llvmorg-14.0.0-rc2
- llvmorg-14.0.0-rc1
- llvmorg-14-init
- llvmorg-13.0.1
- llvmorg-13.0.1-rc3
- llvmorg-13.0.1-rc2
- llvmorg-13.0.1-rc1
- llvmorg-13.0.0
- llvmorg-13.0.0-rc4
- llvmorg-13.0.0-rc3
- llvmorg-13.0.0-rc2
- llvmorg-13.0.0-rc1
- llvmorg-13-init
- llvmorg-12.0.1
- llvmorg-12.0.1-rc4
- llvmorg-12.0.1-rc3
- llvmorg-12.0.1-rc2
- llvmorg-12.0.1-rc1
- llvmorg-12.0.0
- llvmorg-12.0.0-rc5
- llvmorg-12.0.0-rc4
- llvmorg-12.0.0-rc3
- llvmorg-12.0.0-rc2
- llvmorg-12.0.0-rc1
- llvmorg-12-init
- llvmorg-11.1.0
- llvmorg-11.1.0-rc3
- llvmorg-11.1.0-rc2
- llvmorg-11.1.0-rc1
- llvmorg-11.0.1
- llvmorg-11.0.1-rc2
- llvmorg-11.0.1-rc1
- llvmorg-11.0.0
- llvmorg-11.0.0-rc6
- llvmorg-11.0.0-rc5
- llvmorg-11.0.0-rc4
- llvmorg-11.0.0-rc3
- llvmorg-11.0.0-rc2
- llvmorg-11.0.0-rc1
- llvmorg-11-init
- llvmorg-10.0.1
- llvmorg-10.0.1-rc4
- llvmorg-10.0.1-rc3
- llvmorg-10.0.1-rc2
- llvmorg-10.0.1-rc1
- llvmorg-10.0.0
- llvmorg-10.0.0-rc6
- llvmorg-10.0.0-rc5
- llvmorg-10.0.0-rc4
- llvmorg-10.0.0-rc3
- llvmorg-10.0.0-rc2
- llvmorg-10.0.0-rc1
- llvmorg-10-init
- llvmorg-9.0.1
- llvmorg-9.0.1-rc3
- llvmorg-9.0.1-rc2
- llvmorg-9.0.1-rc1
- llvmorg-9.0.0
- llvmorg-9.0.0-rc6
- llvmorg-9.0.0-rc5
- llvmorg-9.0.0-rc4
- llvmorg-9.0.0-rc3
- llvmorg-9.0.0-rc2
- llvmorg-9.0.0-rc1
- llvmorg-8.0.1
- llvmorg-8.0.1-rc4
- llvmorg-8.0.1-rc3
- llvmorg-8.0.1-rc2
- llvmorg-8.0.1-rc1
- llvmorg-8.0.0
- llvmorg-8.0.0-rc5
- llvmorg-8.0.0-rc4
- llvmorg-8.0.0-rc3
- llvmorg-8.0.0-rc2
- llvmorg-8.0.0-rc1
- llvmorg-7.1.0
- llvmorg-7.1.0-rc1
- llvmorg-7.0.1
- llvmorg-7.0.1-rc3
- llvmorg-7.0.1-rc2
- llvmorg-7.0.1-rc1
- llvmorg-7.0.0
- llvmorg-7.0.0-rc3
- llvmorg-7.0.0-rc2
- llvmorg-7.0.0-rc1
- llvmorg-6.0.1
- llvmorg-6.0.1-rc3
- llvmorg-6.0.1-rc2
- llvmorg-6.0.1-rc1
- llvmorg-6.0.0
- llvmorg-6.0.0-rc3
- llvmorg-6.0.0-rc2
- llvmorg-6.0.0-rc1
- llvmorg-5.0.2
- llvmorg-5.0.2-rc2
- llvmorg-5.0.2-rc1
- llvmorg-5.0.1
- llvmorg-5.0.1-rc3
- llvmorg-5.0.1-rc2
- llvmorg-5.0.1-rc1
- llvmorg-5.0.0
- llvmorg-5.0.0-rc5
- llvmorg-5.0.0-rc4
- llvmorg-5.0.0-rc3
- llvmorg-5.0.0-rc2
- llvmorg-5.0.0-rc1
- llvmorg-4.0.1
- llvmorg-4.0.1-rc3
- llvmorg-4.0.1-rc2
- llvmorg-4.0.1-rc1
- llvmorg-4.0.0
- llvmorg-4.0.0-rc4
- llvmorg-4.0.0-rc3
- llvmorg-4.0.0-rc2
- llvmorg-4.0.0-rc1
- llvmorg-3.9.1
- llvmorg-3.9.1-rc3
- llvmorg-3.9.1-rc2
- llvmorg-3.9.1-rc1
- llvmorg-3.9.0
- llvmorg-3.9.0-rc3
- llvmorg-3.9.0-rc2
- llvmorg-3.9.0-rc1
Roger Ferrer Ibanez
committed
Jul 14, 2016
1 parent
34be2a0
commit 585ea9d
Showing
10 changed files
with
474 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify %s | ||
// expected-no-diagnostics | ||
|
||
struct B { | ||
int x, y, z, w; | ||
} b; | ||
|
||
struct __attribute__((packed)) A { | ||
struct B b; | ||
} a; | ||
|
||
typedef __typeof__(sizeof(int)) size_t; | ||
|
||
void *memcpy(void *dest, const void *src, size_t n); | ||
int memcmp(const void *s1, const void *s2, size_t n); | ||
void *memmove(void *dest, const void *src, size_t n); | ||
void *memset(void *s, int c, size_t n); | ||
|
||
int x; | ||
|
||
void foo(void) { | ||
memcpy(&a.b, &b, sizeof(b)); | ||
memmove(&a.b, &b, sizeof(b)); | ||
memset(&a.b, 0, sizeof(b)); | ||
x = memcmp(&a.b, &b, sizeof(b)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify %s | ||
extern void f1(int *); | ||
extern void f2(char *); | ||
|
||
struct Ok { | ||
char c; | ||
int x; | ||
}; | ||
|
||
struct __attribute__((packed)) Arguable { | ||
char c0; | ||
int x; | ||
char c1; | ||
}; | ||
|
||
union __attribute__((packed)) UnionArguable { | ||
char c; | ||
int x; | ||
}; | ||
|
||
typedef struct Arguable ArguableT; | ||
|
||
struct Arguable *get_arguable(); | ||
|
||
void to_void(void *); | ||
|
||
void g0(void) { | ||
{ | ||
struct Ok ok; | ||
f1(&ok.x); // no-warning | ||
f2(&ok.c); // no-warning | ||
} | ||
{ | ||
struct Arguable arguable; | ||
f2(&arguable.c0); // no-warning | ||
f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&arguable.c1); // no-warning | ||
|
||
f1((int *)(void *)&arguable.x); // no-warning | ||
to_void(&arguable.x); // no-warning | ||
void *p = &arguable.x; // no-warning; | ||
to_void(p); | ||
} | ||
{ | ||
union UnionArguable arguable; | ||
f2(&arguable.c); // no-warning | ||
f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'UnionArguable'}} | ||
|
||
f1((int *)(void *)&arguable.x); // no-warning | ||
to_void(&arguable.x); // no-warning | ||
} | ||
{ | ||
ArguableT arguable; | ||
f2(&arguable.c0); // no-warning | ||
f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&arguable.c1); // no-warning | ||
|
||
f1((int *)(void *)&arguable.x); // no-warning | ||
to_void(&arguable.x); // no-warning | ||
} | ||
{ | ||
struct Arguable *arguable = get_arguable(); | ||
f2(&arguable->c0); // no-warning | ||
f1(&arguable->x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&arguable->c1); // no-warning | ||
|
||
f1((int *)(void *)&arguable->x); // no-warning | ||
to_void(&arguable->c1); // no-warning | ||
} | ||
{ | ||
ArguableT *arguable = get_arguable(); | ||
f2(&(arguable->c0)); // no-warning | ||
f1(&(arguable->x)); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&(arguable->c1)); // no-warning | ||
|
||
f1((int *)(void *)&(arguable->x)); // no-warning | ||
to_void(&(arguable->c1)); // no-warning | ||
} | ||
} | ||
|
||
struct S1 { | ||
char c; | ||
int i __attribute__((packed)); | ||
}; | ||
|
||
int *g1(struct S1 *s1) { | ||
return &s1->i; // expected-warning {{packed member 'i' of class or structure 'S1'}} | ||
} | ||
|
||
struct S2_i { | ||
int i; | ||
}; | ||
struct __attribute__((packed)) S2 { | ||
char c; | ||
struct S2_i inner; | ||
}; | ||
|
||
int *g2(struct S2 *s2) { | ||
return &s2->inner.i; // expected-warning {{packed member 'inner' of class or structure 'S2'}} | ||
} | ||
|
||
struct S2_a { | ||
char c; | ||
struct S2_i inner __attribute__((packed)); | ||
}; | ||
|
||
int *g2_a(struct S2_a *s2_a) { | ||
return &s2_a->inner.i; // expected-warning {{packed member 'inner' of class or structure 'S2_a'}} | ||
} | ||
|
||
struct __attribute__((packed)) S3 { | ||
char c; | ||
struct { | ||
int i; | ||
} inner; | ||
}; | ||
|
||
int *g3(struct S3 *s3) { | ||
return &s3->inner.i; // expected-warning {{packed member 'inner' of class or structure 'S3'}} | ||
} | ||
|
||
struct S4 { | ||
char c; | ||
struct __attribute__((packed)) { | ||
int i; | ||
} inner; | ||
}; | ||
|
||
int *g4(struct S4 *s4) { | ||
return &s4->inner.i; // expected-warning {{packed member 'i' of class or structure 'S4::(anonymous)'}} | ||
} | ||
|
||
struct S5 { | ||
char c; | ||
struct { | ||
char c1; | ||
int i __attribute__((packed)); | ||
} inner; | ||
}; | ||
|
||
int *g5(struct S5 *s5) { | ||
return &s5->inner.i; // expected-warning {{packed member 'i' of class or structure 'S5::(anonymous)'}} | ||
} | ||
|
||
struct __attribute__((packed, aligned(2))) AlignedTo2 { | ||
int x; | ||
}; | ||
|
||
char *g6(struct AlignedTo2 *s) { | ||
return (char *)&s->x; // no-warning | ||
} | ||
|
||
struct __attribute__((packed, aligned(2))) AlignedTo2Bis { | ||
int x; | ||
}; | ||
|
||
struct AlignedTo2Bis* g7(struct AlignedTo2 *s) | ||
{ | ||
return (struct AlignedTo2Bis*)&s->x; // no-warning | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// RUN: %clang_cc1 -fsyntax-only -verify %s | ||
// expected-no-diagnostics | ||
|
||
struct B { | ||
int x, y, z, w; | ||
} b; | ||
|
||
struct __attribute__((packed)) A { | ||
struct B b; | ||
} a; | ||
|
||
typedef __typeof__(sizeof(int)) size_t; | ||
|
||
extern "C" { | ||
void *memcpy(void *dest, const void *src, size_t n); | ||
int memcmp(const void *s1, const void *s2, size_t n); | ||
void *memmove(void *dest, const void *src, size_t n); | ||
void *memset(void *s, int c, size_t n); | ||
} | ||
|
||
int x; | ||
|
||
void foo() { | ||
memcpy(&a.b, &b, sizeof(b)); | ||
memmove(&a.b, &b, sizeof(b)); | ||
memset(&a.b, 0, sizeof(b)); | ||
x = memcmp(&a.b, &b, sizeof(b)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s | ||
extern void f1(int *); | ||
extern void f2(char *); | ||
|
||
struct __attribute__((packed)) Arguable { | ||
int x; | ||
char c; | ||
static void foo(); | ||
}; | ||
|
||
extern void f3(void()); | ||
|
||
namespace Foo { | ||
struct __attribute__((packed)) Arguable { | ||
char c; | ||
int x; | ||
static void foo(); | ||
}; | ||
} | ||
|
||
struct Arguable *get_arguable(); | ||
|
||
void f4(int &); | ||
|
||
void to_void(void *); | ||
|
||
template <typename... T> | ||
void sink(T...); | ||
|
||
void g0() { | ||
{ | ||
Foo::Arguable arguable; | ||
f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'Foo::Arguable'}} | ||
f2(&arguable.c); // no-warning | ||
f3(&arguable.foo); // no-warning | ||
|
||
int &w = arguable.x; // expected-error {{binding reference to packed member 'x' of class or structure 'Foo::Arguable'}} | ||
sink(w); | ||
f4(arguable.x); // expected-error {{binding reference to packed member 'x' of class or structure 'Foo::Arguable'}} | ||
|
||
to_void(&arguable.x); // no-warning | ||
void *p1 = &arguable.x; // no-warning | ||
void *p2 = static_cast<void *>(&arguable.x); // no-warning | ||
void *p3 = reinterpret_cast<void *>(&arguable.x); // no-warning | ||
void *p4 = (void *)&arguable.x; // no-warning | ||
sink(p1, p2, p3, p4); | ||
} | ||
{ | ||
Arguable arguable1; | ||
Arguable &arguable(arguable1); | ||
f1(&arguable.x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&arguable.c); // no-warning | ||
f3(&arguable.foo); // no-warning | ||
} | ||
{ | ||
Arguable *arguable1; | ||
Arguable *&arguable(arguable1); | ||
f1(&arguable->x); // expected-warning {{packed member 'x' of class or structure 'Arguable'}} | ||
f2(&arguable->c); // no-warning | ||
f3(&arguable->foo); // no-warning | ||
} | ||
} | ||
|
||
struct __attribute__((packed)) A { | ||
int x; | ||
char c; | ||
|
||
int *f0() { | ||
return &this->x; // expected-warning {{packed member 'x' of class or structure 'A'}} | ||
} | ||
|
||
int *g0() { | ||
return &x; // expected-warning {{packed member 'x' of class or structure 'A'}} | ||
} | ||
|
||
char *h0() { | ||
return &c; // no-warning | ||
} | ||
}; | ||
|
||
struct B : A { | ||
int *f1() { | ||
return &this->x; // expected-warning {{packed member 'x' of class or structure 'A'}} | ||
} | ||
|
||
int *g1() { | ||
return &x; // expected-warning {{packed member 'x' of class or structure 'A'}} | ||
} | ||
|
||
char *h1() { | ||
return &c; // no-warning | ||
} | ||
}; | ||
|
||
template <typename Ty> | ||
class __attribute__((packed)) S { | ||
Ty X; | ||
|
||
public: | ||
const Ty *get() const { | ||
return &X; // expected-warning {{packed member 'X' of class or structure 'S<int>'}} | ||
// expected-warning@-1 {{packed member 'X' of class or structure 'S<float>'}} | ||
} | ||
}; | ||
|
||
template <typename Ty> | ||
void h(Ty *); | ||
|
||
void g1() { | ||
S<int> s1; | ||
s1.get(); // expected-note {{in instantiation of member function 'S<int>::get'}} | ||
|
||
S<char> s2; | ||
s2.get(); | ||
|
||
S<float> s3; | ||
s3.get(); // expected-note {{in instantiation of member function 'S<float>::get'}} | ||
} |