[PATCH] D32456: [ubsan] Make the alignment check work with some extern decls (PR32630)

Vedant Kumar via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 24 15:57:14 PDT 2017


vsk created this revision.

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.


https://reviews.llvm.org/D32456

Files:
  lib/CodeGen/CodeGenModule.cpp
  test/CodeGenCXX/ubsan-global-alignment.cpp


Index: test/CodeGenCXX/ubsan-global-alignment.cpp
===================================================================
--- test/CodeGenCXX/ubsan-global-alignment.cpp
+++ test/CodeGenCXX/ubsan-global-alignment.cpp
@@ -5,18 +5,27 @@
 };
 
 extern S g_S;
+__private_extern__ S pe_S;
 extern S array_S[];
 
-// CHECK-LABEL: define i32 @_Z18load_extern_global
-int load_extern_global() {
-  // FIXME: The IR builder constant-folds the alignment check away to 'true'
-  // here, so we never call the diagnostic. This is PR32630.
-  // CHECK-NOT: ptrtoint i32* {{.*}} to i32, !nosanitize
+// CHECK-LABEL: define i32 @_Z19load_extern_global1
+int load_extern_global1() {
+  // CHECK: br i1 icmp eq (i64 and (i64 ptrtoint (%struct.S* @g_S to i64), i64 3), i64 0), {{.*}}, !nosanitize
+  // CHECK: call void @__ubsan_handle_type_mismatch
   // CHECK: [[I:%.*]] = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @g_S, i32 0, i32 0), align 4
   // CHECK-NEXT: ret i32 [[I]]
   return g_S.I;
 }
 
+// CHECK-LABEL: define i32 @_Z19load_extern_global2
+int load_extern_global2() {
+  // CHECK: br i1 icmp eq (i64 and (i64 ptrtoint (%struct.S* @pe_S to i64), i64 3), i64 0), {{.*}}, !nosanitize
+  // CHECK: call void @__ubsan_handle_type_mismatch
+  // CHECK: [[I:%.*]] = load i32, i32* getelementptr inbounds (%struct.S, %struct.S* @pe_S, i32 0, i32 0), align 4
+  // CHECK-NEXT: ret i32 [[I]]
+  return pe_S.I;
+}
+
 // CHECK-LABEL: define i32 @_Z22load_from_extern_array
 int load_from_extern_array(int I) {
   // CHECK: [[I:%.*]] = getelementptr inbounds %struct.S, %struct.S* {{.*}}, i32 0, i32 0
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -2312,7 +2312,14 @@
     // handling.
     GV->setConstant(isTypeConstant(D->getType(), false));
 
-    GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
+    if (LangOpts.Sanitize.has(SanitizerKind::Alignment) && !IsForDefinition &&
+        (D->getStorageClass() == SC_Extern ||
+         D->getStorageClass() == SC_PrivateExtern)) {
+      // The alignment sanitizer can catch more bugs if we don't attach
+      // alignment info to extern globals.
+    } else {
+      GV->setAlignment(getContext().getDeclAlign(D).getQuantity());
+    }
 
     setLinkageAndVisibilityForGV(GV, D);
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D32456.96480.patch
Type: text/x-patch
Size: 2376 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170424/4a8254c0/attachment.bin>


More information about the cfe-commits mailing list