kuhar created this revision.
kuhar added a subscriber: cfe-commits.
kuhar set the repository for this revision to rL LLVM.

Previously, using __attribute__((section("bss.name")) incorrectly caused clang 
to crash displaying error from backed. This patch makes clang's frontend 
produce clear diagnostic/error.

Two main cases that are handled is using the attribute with functions and with 
variables initialized to non-zero values.
`__attribute__((section(".bss.name"))) void func() { }`
`__attribute__((section(".bss.name"))) int a = 3;`


Repository:
  rL LLVM

http://reviews.llvm.org/D11221

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Sema/attr-section-bss.c

Index: test/Sema/attr-section-bss.c
===================================================================
--- /dev/null
+++ test/Sema/attr-section-bss.c
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+
+__attribute__((section(".bss.Name"))) int a = 3 * 5; // expected-error {{variable placed in BSS section (".bss.Name") must be zero-initialized, but 'a' is initialized with non-zero value}}
+__attribute__((section(".bss.Name"))) int correct_a = 0 * 5;
+
+__attribute__((section(".bss.Name"))) float x = 3.0 * 0.997; // expected-error {{variable placed in BSS section (".bss.Name") must be zero-initialized, but 'x' is initialized with non-zero value}}
+__attribute__((section(".bss.Name"))) float correct_x = 0.0 * 0.997;
+
+__attribute__((section(".bss.Sth"))) void foo() {} // expected-error {{functions cannot be placed in BSS section (".bss.Sth")}}
+
+__attribute__((section(".bss.Name"))) int arr[] = {0, 2, 0}; // expected-error {{variable placed in BSS section (".bss.Name") must be zero-initialized, but 'arr' is initialized with non-zero value}}
+__attribute__((section(".bss.Name"))) int correct_arr[] = {0, 0, 0};
+
+typedef struct {
+  float a;
+  int b;
+  double arr[3];
+} TestStruct;
+
+__attribute__((section(".bss"))) TestStruct str = {0.0, 0, {0.0, 1.0, 0.0}}; // expected-error {{variable placed in BSS section (".bss") must be zero-initialized, but 'str' is initialized with non-zero value}}
+__attribute__((section(".bss"))) TestStruct correct_str = {0.0, 0, {0.0, 0.0, 0.0}};
+
+typedef struct {} EmptyStruct;
+__attribute__((section(".bss.Name"))) EmptyStruct estr = {};
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -2396,6 +2396,12 @@
   SectionAttr *NewAttr = S.mergeSectionAttr(D, Attr.getRange(), Str, Index);
   if (NewAttr)
     D->addAttr(NewAttr);
+
+  if (isa<FunctionDecl>(D) && Str.startswith(".bss")) {
+    S.Diag(Attr.getRange().getEnd(), diag::err_attribute_section_bss_function)
+        << Str << NewAttr->getRange();
+    D->dropAttr<SectionAttr>();
+  }
 }
 
 // Check for things we'd like to warn about, no errors or validation for now.
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -5302,6 +5302,103 @@
   return false;
 }
 
+static bool isValueNonZero(APValue &Value) {
+  switch (Value.getKind()) {
+  case APValue::Uninitialized:
+    return false;
+  case APValue::Int:
+    return Value.getInt() != 0;
+  case APValue::Float:
+    return Value.getFloat().isNonZero();
+  case APValue::ComplexInt: {
+    bool isRealNonZero = Value.getComplexIntReal() != 0;
+    bool isImagNonZero = Value.getComplexIntImag() != 0;
+    return isRealNonZero || isImagNonZero;
+  }
+  case APValue::ComplexFloat: {
+    bool isRealNonZero = Value.getComplexFloatReal().isNonZero();
+    bool isImagNonZero = Value.getComplexFloatImag().isNonZero();
+    return isRealNonZero || isImagNonZero;
+  }
+  case APValue::Vector: {
+    for (unsigned i = 0, e = Value.getVectorLength(); i < e; ++i) {
+      if (isValueNonZero(Value.getVectorElt(i)))
+        return true;
+    }
+    return false;
+  }
+  case APValue::Array: {
+    for (unsigned i = 0, e = Value.getArrayInitializedElts(); i < e; ++i) {
+      if (isValueNonZero(Value.getArrayInitializedElt(i)))
+        return true;
+    }
+    return false;
+  }
+  case APValue::Struct: {
+    for (unsigned i = 0, e = Value.getStructNumBases(); i < e; ++i) {
+      if (isValueNonZero(Value.getStructBase(i)))
+        return true;
+    }
+    for (unsigned i = 0, e = Value.getStructNumFields(); i < e; ++i) {
+      if (isValueNonZero(Value.getStructField(i)))
+        return true;
+    }
+    return false;
+  }
+  case APValue::Union:
+    return isValueNonZero(Value.getUnionValue());
+
+  // For other kinds we cannot tell and assume non-zero.
+  case APValue::LValue:
+    return false;
+  case APValue::MemberPointer:
+    return false;
+  case APValue::AddrLabelDiff:
+    return false;
+  }
+
+  llvm_unreachable("unhandled APValue kind");
+}
+
+static bool isExpressionNonZero(const Expr *E, Sema &S, VarDecl &VD) {
+  APValue Result;
+  SmallVector<PartialDiagnosticAt, 2> Notes;
+  if (E->EvaluateAsInitializer(Result, S.Context, &VD, Notes))
+    return isValueNonZero(Result);
+
+  if (auto *InitList = dyn_cast<InitListExpr>(E)) {
+    for (Stmt *Statement : *InitList) {
+      if (auto *InitElt = dyn_cast<Expr>(Statement)) {
+        if (InitElt->EvaluateAsInitializer(Result, S.Context, &VD, Notes)) {
+          if (isExpressionNonZero(InitElt, S, VD))
+            return true;
+        } else if (isExpressionNonZero(InitElt, S, VD))
+          return true;
+      } else
+        return true;
+    }
+    return false;
+  }
+  return true; // Expr E is neither evaluable initializer nor initializer list.
+}
+
+static void checkAttributeSectionBSS(Sema &S, VarDecl &VD) {
+  if (auto *SA = VD.getAttr<SectionAttr>()) {
+    if (SA->getName().startswith(".bss")) {
+      if (const Expr *InitExpr = VD.getInit()) {
+        if (isExpressionNonZero(InitExpr, S, VD)) {
+          S.Diag(SA->getRange().getEnd(),
+                 diag::err_attribute_section_bss_nonzero)
+              << SA->getName() << VD.getName() << SA->getRange()
+              << InitExpr->getSourceRange();
+
+          VD.dropAttr<SectionAttr>();
+        }
+      }
+    }
+  }
+}
+
 static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
   // Ensure that an auto decl is deduced otherwise the checks below might cache
   // the wrong linkage.
@@ -5330,6 +5427,7 @@
         S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD;
         VD->dropAttr<AliasAttr>();
       }
+      checkAttributeSectionBSS(S, *VD);
     }
   }
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2176,6 +2176,11 @@
   "argument to 'section' attribute is not valid for this target: %0">;
 def warn_mismatched_section : Warning<
   "section does not match previous declaration">, InGroup<Section>;
+def err_attribute_section_bss_nonzero : Error<
+  "variable placed in BSS section (\"%0\") must be zero-initialized, but "
+  "\'%1\' is initialized with non-zero value">;
+def err_attribute_section_bss_function : Error<
+  "functions cannot be placed in BSS section (\"%0\")">;
 
 def err_anonymous_property: Error<
   "anonymous property is not supported">;
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to