Skip to content

Commit 8c48be8

Browse files
committed
Enable UOD warning for windows
1 parent 65d5301 commit 8c48be8

File tree

5 files changed

+115
-54
lines changed

5 files changed

+115
-54
lines changed

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,9 @@ def UniqueObjectDuplication : DiagGroup<"unique-object-duplication"> {
806806
Warns when objects which are supposed to be globally unique might get duplicated
807807
when built into a shared library.
808808

809-
If an object with hidden visibility is built into a shared library, each instance
809+
This can occur to objects which are hidden from the dynamic linker, due to
810+
having hidden visibility (on posix) or lacking an import/export annotation (on
811+
windows). If such an object is built into a shared library, each instance
810812
of the library will get its own copy. This can cause very subtle bugs if there was
811813
only supposed to be one copy of the object in question: singletons aren't single,
812814
changes to one object won't affect the others, the object's initializer will run
@@ -815,7 +817,7 @@ once per copy, etc.
815817
Specifically, this warning fires when it detects an object which:
816818
1. Is defined as ``inline`` in a header file (so it might get compiled into multiple libaries), and
817819
2. Has external linkage (otherwise it's supposed to be duplicated), and
818-
3. Has hidden visibility.
820+
3. Has hidden visibility (posix) or lacks an import/export annotation (windows).
819821

820822
As well as one of the following:
821823
1. The object is mutable, or
@@ -825,13 +827,15 @@ The warning can be resolved by removing one of the conditions above. In rough
825827
order of preference, this may be done by:
826828
1. Marking the object ``const`` (if possible)
827829
2. Moving the object's definition to a source file
828-
3. Giving the object non-hidden visibility, e.g. using ``__attribute((visibility("default")))``.
830+
3. Making the object visible using ``__attribute((visibility("default")))``,
831+
``__declspec(dllimport)``, or ``__declspec(dllexport)``.
832+
833+
When annotating an object with ``__declspec(dllimport)`` or ``__declspec(dllexport)``,
834+
take care to ensure that the object is only imported in one dll, and is exported
835+
everywhere else.
829836

830837
Note that for (2), all levels of a pointer variable must be constant;
831838
``const int*`` will trigger the warning because the pointer itself is mutable.
832-
833-
This warning is not yet implemented for Windows, since Windows uses
834-
import/export rules instead of visibility.
835839
}];
836840
}
837841

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6260,14 +6260,19 @@ def warn_static_local_in_extern_inline : Warning<
62606260
def note_convert_inline_to_static : Note<
62616261
"use 'static' to give inline function %0 internal linkage">;
62626262

6263-
def warn_possible_object_duplication_mutable : Warning<
6264-
"%0 may be duplicated when built into a shared library: "
6265-
"it is mutable, has hidden visibility, and external linkage">,
6266-
InGroup<UniqueObjectDuplication>, DefaultIgnore;
6267-
def warn_possible_object_duplication_init : Warning<
6268-
"initialization of %0 may run twice when built into a shared library: "
6269-
"it has hidden visibility and external linkage">,
6270-
InGroup<UniqueObjectDuplication>, DefaultIgnore;
6263+
def warn_possible_object_duplication_mutable
6264+
: Warning<"%0 may be duplicated when built into a shared library: "
6265+
"it is mutable, with external linkage and "
6266+
"%select{hidden visibility|no import/export annotation}1">,
6267+
InGroup<UniqueObjectDuplication>,
6268+
DefaultIgnore;
6269+
def warn_possible_object_duplication_init
6270+
: Warning<"initialization of %0 may run twice when built into a shared "
6271+
"library: "
6272+
"it has external linkage and "
6273+
"%select{hidden visibility|no import/export annotation}1">,
6274+
InGroup<UniqueObjectDuplication>,
6275+
DefaultIgnore;
62716276

62726277
def ext_redefinition_of_typedef : ExtWarn<
62736278
"redefinition of typedef %0 is a C11 feature">,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13518,8 +13518,29 @@ bool Sema::GloballyUniqueObjectMightBeAccidentallyDuplicated(
1351813518

1351913519
// If the object isn't hidden, the dynamic linker will prevent duplication.
1352013520
clang::LinkageInfo Lnk = Target->getLinkageAndVisibility();
13521-
if (Lnk.getVisibility() != HiddenVisibility)
13521+
13522+
// The target is "hidden" (from the dynamic linker) if:
13523+
// 1. On posix, it has hidden visibility, or
13524+
// 2. On windows, it has no import/export annotation
13525+
if (Context.getTargetInfo().shouldDLLImportComdatSymbols()) {
13526+
if (Target->hasAttr<DLLExportAttr>() || Target->hasAttr<DLLImportAttr>())
13527+
return false;
13528+
13529+
// If the variable isn't directly annotated, check to see if it's a member
13530+
// of an annotated class.
13531+
const VarDecl *VD = dyn_cast_if_present<VarDecl>(Target);
13532+
13533+
if (VD && VD->isStaticDataMember()) {
13534+
const CXXRecordDecl *Ctx =
13535+
dyn_cast_if_present<CXXRecordDecl>(VD->getDeclContext());
13536+
if (Ctx &&
13537+
(Ctx->hasAttr<DLLExportAttr>() || Ctx->hasAttr<DLLImportAttr>()))
13538+
return false;
13539+
}
13540+
} else if (Lnk.getVisibility() != HiddenVisibility) {
13541+
// Posix case
1352213542
return false;
13543+
}
1352313544

1352413545
// If the obj doesn't have external linkage, it's supposed to be duplicated.
1352513546
if (!isExternalFormalLinkage(Lnk.getLinkage()))
@@ -13550,19 +13571,16 @@ void Sema::DiagnoseUniqueObjectDuplication(const VarDecl *VD) {
1355013571
// duplicated when built into a shared library, which causes problems if it's
1355113572
// mutable (since the copies won't be in sync) or its initialization has side
1355213573
// effects (since it will run once per copy instead of once globally).
13553-
// FIXME: Windows uses dllexport/dllimport instead of visibility, and we don't
13554-
// handle that yet. Disable the warning on Windows for now.
1355513574

1355613575
// Don't diagnose if we're inside a template, because it's not practical to
1355713576
// fix the warning in most cases.
13558-
if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() &&
13559-
!VD->isTemplated() &&
13577+
if (!VD->isTemplated() &&
1356013578
GloballyUniqueObjectMightBeAccidentallyDuplicated(VD)) {
1356113579

1356213580
QualType Type = VD->getType();
1356313581
if (looksMutable(Type, VD->getASTContext())) {
1356413582
Diag(VD->getLocation(), diag::warn_possible_object_duplication_mutable)
13565-
<< VD;
13583+
<< VD << Context.getTargetInfo().shouldDLLImportComdatSymbols();
1356613584
}
1356713585

1356813586
// To keep false positives low, only warn if we're certain that the
@@ -13575,7 +13593,7 @@ void Sema::DiagnoseUniqueObjectDuplication(const VarDecl *VD) {
1357513593
/*IncludePossibleEffects=*/false) &&
1357613594
!isa<CXXNewExpr>(Init->IgnoreParenImpCasts())) {
1357713595
Diag(Init->getExprLoc(), diag::warn_possible_object_duplication_init)
13578-
<< VD;
13596+
<< VD << Context.getTargetInfo().shouldDLLImportComdatSymbols();
1357913597
}
1358013598
}
1358113599
}

clang/test/SemaCXX/unique_object_duplication.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
// RUN: %clang_cc1 -fsyntax-only -verify=hidden -Wunique-object-duplication -fvisibility=hidden -Wno-unused-value %s
2-
// RUN: %clang_cc1 -fsyntax-only -verify -Wunique-object-duplication -Wno-unused-value %s
3-
// The check is currently disabled on windows in MSVC-like environments. The test should fail because we're not getting the expected warnings.
4-
// XFAIL: target={{.*}}-windows-msvc, {{.*}}-ps{{(4|5)(-.+)?}}
1+
// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \
2+
// RUN: -verify -triple=x86_64-pc-linux-gnu %s
3+
// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \
4+
// RUN: -verify=hidden -triple=x86_64-pc-linux-gnu -fvisibility=hidden %s
5+
// RUN: %clang_cc1 -fsyntax-only -Wunique-object-duplication -Wno-unused-value \
6+
// RUN: -verify=windows -triple=x86_64-windows-msvc -DWINDOWS_TEST -fdeclspec %s
57

68
#include "unique_object_duplication.h"
79

0 commit comments

Comments
 (0)