This is an archive of the discontinued LLVM Phabricator instance.

[ubsan] Make the alignment check work with some extern decls (PR32630)
Needs ReviewPublic

Authored by vsk on Apr 24 2017, 3:57 PM.

Details

Summary

UBSan's alignment check does not detect unaligned loads and stores from
extern struct declarations. Example:

struct S { int i; };
extern struct S g_S; // &g_S may not be aligned properly.

int main() {
  return g_S.i; // No alignment check for &g_S.i is emitted.
}

The frontend skips the alignment check for &g_S.i because the check is
constant-folded to 'NOT NULL' by the IR builder.

If we drop the alignment information from extern struct declarations,
the IR builder would no longer be able to constant-fold the checks away.
That would make the alignment check more useful.

Note: it would still not be able to catch the following case --

extern int i; // &i is not aligned properly.

PR: https://bugs.llvm.org/show_bug.cgi?id=32630

Testing: check-clang, check-ubsan.

Diff Detail

Event Timeline

vsk created this revision.Apr 24 2017, 3:57 PM

Note: it would still not be able to catch the following case --

Do you know why?

lib/CodeGen/CodeGenModule.cpp
2319

If we don't explicitly set the alignment, is it 1? Or is it picking up the alignment from the type somehow?

vsk added a comment.Apr 24 2017, 10:35 PM

Note: it would still not be able to catch the following case --

Do you know why?

As-written, the alignment check doesn't apply to loads and stores on non-pointer POD types. The reason why is probably that most of these loads/stores happen on the stack, where the data should be aligned.

lib/CodeGen/CodeGenModule.cpp
2319

If the alignment isn't explicitly set, it is initialized to 0. The LangRef states: 'Either global variable definitions or declarations may have an explicit section to be placed in and may have an optional explicit alignment specified'. It should be OK to not specify the alignment.

If the alignment isn't explicitly set, it is initialized to 0.

That's what I thought. I don't like this; clang should explicitly set an alignment for every global.

vsk added a comment.Apr 25 2017, 1:18 PM

If the alignment isn't explicitly set, it is initialized to 0.

That's what I thought. I don't like this; clang should explicitly set an alignment for every global.

Ok, I will set this aside for now and think of an alternate approach to address PR32630.

Err, that's not what I meant...

If the alignment of a global in LLVM IR is "zero", it doesn't really mean zero. It means "guess the alignment I want based on the specified type of the global". And that's not a game we ever want to play when generating IR from clang.

vsk added a comment.Apr 25 2017, 2:03 PM

Err, that's not what I meant...

If the alignment of a global in LLVM IR is "zero", it doesn't really mean zero. It means "guess the alignment I want based on the specified type of the global". And that's not a game we ever want to play when generating IR from clang.

The alternative mentioned in PR32630 is to decrease the alignment of the global when -fsanitize=alignment is enabled. Is this less risky than not specifying the alignment at all? I assumed that it was not.

Hm, giving this more thought I'm not happy with how fragile this patch seems. Changing the way we set alignment to hack around constant folding doesn't seem great. And this patch does not interact properly with extern definitions which have 'attribute((aligned(N)))' set.

This should work correctly with alignment attributes, I think? IIRC those just change the return value of getDeclAlign().

I agree it's a little fragile, but I don't have a good suggestion to avoid that.