Skip to content

Commit ff56308

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:5099dc341f7f into amd-gfx:ab27814b3805
Local branch amd-gfx ab27814 Merged main:7539bcf994ed into amd-gfx:0e8798f5c1bd Remote branch main 5099dc3 [Clang][CodeGen] Fix use of CXXThisValue with StrictVTablePointers (llvm#68169)
2 parents ab27814 + 5099dc3 commit ff56308

File tree

62 files changed

+6449
-1151
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+6449
-1151
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4287,7 +4287,7 @@ def mcmodel_EQ : Joined<["-"], "mcmodel=">, Group<m_Group>,
42874287
MarshallingInfoString<TargetOpts<"CodeModel">, [{"default"}]>;
42884288
def mlarge_data_threshold_EQ : Joined<["-"], "mlarge-data-threshold=">, Group<m_Group>,
42894289
Visibility<[ClangOption, CC1Option]>,
4290-
MarshallingInfoInt<TargetOpts<"LargeDataThreshold">>;
4290+
MarshallingInfoInt<TargetOpts<"LargeDataThreshold">, "65535">;
42914291
def mtls_size_EQ : Joined<["-"], "mtls-size=">, Group<m_Group>,
42924292
Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
42934293
HelpText<"Specify bit size of immediate TLS offsets (AArch64 ELF only): "

clang/lib/CodeGen/CGClass.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "clang/CodeGen/CGFunctionInfo.h"
2929
#include "llvm/IR/Intrinsics.h"
3030
#include "llvm/IR/Metadata.h"
31+
#include "llvm/Support/SaveAndRestore.h"
3132
#include "llvm/Transforms/Utils/SanitizerStats.h"
3233
#include <optional>
3334

@@ -1291,10 +1292,10 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
12911292
assert(BaseCtorContinueBB);
12921293
}
12931294

1294-
llvm::Value *const OldThis = CXXThisValue;
12951295
for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) {
12961296
if (!ConstructVBases)
12971297
continue;
1298+
SaveAndRestore ThisRAII(CXXThisValue);
12981299
if (CGM.getCodeGenOpts().StrictVTablePointers &&
12991300
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
13001301
isInitializerOfDynamicClass(*B))
@@ -1311,16 +1312,14 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
13111312
// Then, non-virtual base initializers.
13121313
for (; B != E && (*B)->isBaseInitializer(); B++) {
13131314
assert(!(*B)->isBaseVirtual());
1314-
1315+
SaveAndRestore ThisRAII(CXXThisValue);
13151316
if (CGM.getCodeGenOpts().StrictVTablePointers &&
13161317
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
13171318
isInitializerOfDynamicClass(*B))
13181319
CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
13191320
EmitBaseInitializer(*this, ClassDecl, *B);
13201321
}
13211322

1322-
CXXThisValue = OldThis;
1323-
13241323
InitializeVTablePointers(ClassDecl);
13251324

13261325
// And finally, initialize class members.

clang/lib/Format/WhitespaceManager.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
354354
}
355355
}
356356

357+
if (Shift == 0)
358+
continue;
359+
357360
// This is for function parameters that are split across multiple lines,
358361
// as mentioned in the ScopeStack comment.
359362
if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) {
@@ -447,7 +450,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
447450
CurrentChange.Spaces += Shift;
448451

449452
// We should not remove required spaces unless we break the line before.
450-
assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 ||
453+
assert(Shift > 0 || Changes[i].NewlinesBefore > 0 ||
451454
CurrentChange.Spaces >=
452455
static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||
453456
CurrentChange.Tok->is(tok::eof));

clang/test/CodeGen/large-data-threshold.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=200 | FileCheck %s --check-prefix=ASM-SMALL
66
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -S %s -o - -mcmodel=medium -mlarge-data-threshold=2 | FileCheck %s --check-prefix=ASM-LARGE
77

8-
// IR-DEFAULT: !{i32 1, !"Large Data Threshold", i64 0}
8+
// IR-DEFAULT: !{i32 1, !"Large Data Threshold", i64 65535}
99
// IR-CUSTOM: !{i32 1, !"Large Data Threshold", i64 200}
1010

1111
// ASM-SMALL-NOT: movabsq
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 %s -I%S -triple=x86_64-pc-windows-msvc -fstrict-vtable-pointers -disable-llvm-passes -O1 -emit-llvm -o %t.ll
2+
// RUN: FileCheck %s < %t.ll
3+
4+
struct A {
5+
virtual ~A();
6+
};
7+
struct B : virtual A {};
8+
class C : B {};
9+
C foo;
10+
11+
// CHECK-LABEL: define {{.*}} @"??0C@@QEAA@XZ"(ptr {{.*}} %this, i32 {{.*}} %is_most_derived)
12+
// CHECK: ctor.init_vbases:
13+
// CHECK-NEXT: %0 = getelementptr inbounds i8, ptr %this1, i64 0
14+
// CHECK-NEXT: store ptr @"??_8C@@7B@", ptr %0
15+
// CHECK-NEXT: %1 = call ptr @llvm.launder.invariant.group.p0(ptr %this1)
16+
// CHECK-NEXT: %2 = getelementptr inbounds i8, ptr %1, i64 8
17+
// CHECK-NEXT: %call = call noundef ptr @"??0A@@QEAA@XZ"(ptr {{.*}} %2) #2
18+
// CHECK-NEXT: br label %ctor.skip_vbases
19+
// CHECK-EMPTY:
20+
// CHECK-NEXT: ctor.skip_vbases:
21+
// CHECK-NEXT: %3 = call ptr @llvm.launder.invariant.group.p0(ptr %this1)
22+
// CHECK-NEXT: %call3 = call noundef ptr @"??0B@@QEAA@XZ"(ptr {{.*}} %3, i32 noundef 0) #2

libc/src/__support/float_to_string.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ FloatToString<long double>::get_negative_block(int block_index) {
708708
const int32_t SHIFT_CONST = TABLE_SHIFT_CONST;
709709

710710
// if the requested block is zero
711-
if (block_index <= MIN_BLOCK_2[idx]) {
711+
if (block_index < MIN_BLOCK_2[idx]) {
712712
return 0;
713713
}
714714
const uint32_t p = POW10_OFFSET_2[idx] + block_index - MIN_BLOCK_2[idx];

libc/startup/linux/x86_64/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ add_startup_object(
1010
libc.src.__support.threads.thread
1111
libc.src.__support.OSUtil.osutil
1212
libc.src.stdlib.exit
13+
libc.src.stdlib.abort
1314
libc.src.stdlib.atexit
1415
libc.src.string.memory_utils.inline_memcpy
1516
libc.src.unistd.environ

libc/startup/linux/x86_64/start.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "config/linux/app.h"
10+
#include "src/__support/OSUtil/io.h"
1011
#include "src/__support/OSUtil/syscall.h"
1112
#include "src/__support/threads/thread.h"
13+
#include "src/stdlib/abort.h"
1214
#include "src/stdlib/atexit.h"
1315
#include "src/stdlib/exit.h"
1416
#include "src/string/memory_utils/inline_memcpy.h"
@@ -23,6 +25,11 @@
2325

2426
extern "C" int main(int, char **, char **);
2527

28+
extern "C" void __stack_chk_fail() {
29+
LIBC_NAMESPACE::write_to_stderr("stack smashing detected");
30+
LIBC_NAMESPACE::abort();
31+
}
32+
2633
namespace LIBC_NAMESPACE {
2734

2835
#ifdef SYS_mmap2
@@ -54,7 +61,9 @@ void init_tls(TLSDescriptor &tls_descriptor) {
5461
// Per the x86_64 TLS ABI, the entry pointed to by the thread pointer is the
5562
// address of the TLS block. So, we add more size to accomodate this address
5663
// entry.
57-
uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t);
64+
// We also need to include space for the stack canary. The canary is at
65+
// offset 0x28 (40) and is of size uintptr_t.
66+
uintptr_t tlsSizeWithAddr = tlsSize + sizeof(uintptr_t) + 40;
5867

5968
// We cannot call the mmap function here as the functions set errno on
6069
// failure. Since errno is implemented via a thread local variable, we cannot
@@ -76,6 +85,16 @@ void init_tls(TLSDescriptor &tls_descriptor) {
7685
LIBC_NAMESPACE::inline_memcpy(reinterpret_cast<char *>(tlsAddr),
7786
reinterpret_cast<const char *>(app.tls.address),
7887
app.tls.init_size);
88+
uintptr_t *stackGuardAddr = reinterpret_cast<uintptr_t *>(endPtr + 40);
89+
// Setting the stack guard to a random value.
90+
// We cannot call the get_random function here as the function sets errno on
91+
// failure. Since errno is implemented via a thread local variable, we cannot
92+
// use errno before TLS is setup.
93+
ssize_t stackGuardRetVal = LIBC_NAMESPACE::syscall_impl<ssize_t>(
94+
SYS_getrandom, reinterpret_cast<long>(stackGuardAddr), sizeof(uint64_t),
95+
0);
96+
if (stackGuardRetVal < 0)
97+
LIBC_NAMESPACE::syscall_impl(SYS_exit, 1);
7998

8099
tls_descriptor = {tlsSizeWithAddr, uintptr_t(tlsAddr), endPtr};
81100
return;

libc/test/integration/src/unistd/CMakeLists.txt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,29 @@ add_integration_test(
3333
libc.src.unistd.fork
3434
)
3535

36+
if((${LIBC_TARGET_OS} STREQUAL "linux") AND (${LIBC_TARGET_ARCHITECTURE_IS_X86}))
37+
add_integration_test(
38+
stack_smashing_test
39+
SUITE
40+
unistd-integration-tests
41+
SRCS
42+
stack_smashing_test.cpp
43+
DEPENDS
44+
libc.include.errno
45+
libc.include.signal
46+
libc.include.sys_wait
47+
libc.include.unistd
48+
libc.src.pthread.pthread_atfork
49+
libc.src.signal.raise
50+
libc.src.sys.wait.wait
51+
libc.src.sys.wait.wait4
52+
libc.src.sys.wait.waitpid
53+
libc.src.unistd.fork
54+
COMPILE_OPTIONS
55+
-fstack-protector-all
56+
)
57+
endif()
58+
3659
add_executable(
3760
libc_execv_test_normal_exit
3861
EXCLUDE_FROM_ALL
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===--- Stack smashing test to check stack canary set up ----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/__support/CPP/string.h"
10+
#include "src/__support/OSUtil/io.h"
11+
#include "src/pthread/pthread_atfork.h"
12+
#include "src/signal/raise.h"
13+
#include "src/sys/wait/wait.h"
14+
#include "src/sys/wait/wait4.h"
15+
#include "src/sys/wait/waitpid.h"
16+
#include "src/unistd/fork.h"
17+
18+
#include "test/IntegrationTest/test.h"
19+
20+
#include <errno.h>
21+
#include <signal.h>
22+
#include <sys/wait.h>
23+
#include <unistd.h>
24+
25+
void no_stack_smashing_normal_exit() {
26+
pid_t pid = LIBC_NAMESPACE::fork();
27+
if (pid == 0) {
28+
// Child process
29+
char foo[30];
30+
for (int i = 0; i < 30; i++)
31+
foo[i] = (foo[i] != 42) ? 42 : 24;
32+
return;
33+
}
34+
ASSERT_TRUE(pid > 0);
35+
int status;
36+
pid_t cpid = LIBC_NAMESPACE::wait(&status);
37+
ASSERT_TRUE(cpid > 0);
38+
ASSERT_EQ(cpid, pid);
39+
ASSERT_TRUE(WIFEXITED(status));
40+
}
41+
42+
void stack_smashing_abort() {
43+
pid_t pid = LIBC_NAMESPACE::fork();
44+
if (pid == 0) {
45+
// Child process
46+
char foo[30];
47+
char *frame_ptr = static_cast<char *>(__builtin_frame_address(0));
48+
char *cur_ptr = &foo[0];
49+
// Corrupt the stack
50+
while (cur_ptr != frame_ptr) {
51+
*cur_ptr = (*cur_ptr != 42) ? 42 : 24;
52+
cur_ptr++;
53+
}
54+
return;
55+
}
56+
ASSERT_TRUE(pid > 0);
57+
int status;
58+
pid_t cpid = LIBC_NAMESPACE::wait(&status);
59+
ASSERT_TRUE(cpid > 0);
60+
ASSERT_EQ(cpid, pid);
61+
ASSERT_TRUE(WTERMSIG(status) == SIGABRT);
62+
}
63+
64+
TEST_MAIN(int argc, char **argv, char **envp) {
65+
no_stack_smashing_normal_exit();
66+
stack_smashing_abort();
67+
return 0;
68+
}

libc/test/src/stdio/sprintf_test.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,6 +2433,9 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
24332433
written = LIBC_NAMESPACE::sprintf(buff, "%g", 9999999000000.00);
24342434
ASSERT_STREQ_LEN(written, buff, "1e+13");
24352435

2436+
written = LIBC_NAMESPACE::sprintf(buff, "%g", 0xa.aaaaaaaaaaaaaabp-7);
2437+
ASSERT_STREQ_LEN(written, buff, "0.0833333");
2438+
24362439
// Simple Subnormal Tests.
24372440

24382441
written = LIBC_NAMESPACE::sprintf(buff, "%g", 0x1.0p-1027);
@@ -2457,9 +2460,16 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
24572460

24582461
// Length Modifier Tests.
24592462

2463+
#if defined(SPECIAL_X86_LONG_DOUBLE)
2464+
24602465
written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 0xf.fffffffffffffffp+16380L);
24612466
ASSERT_STREQ_LEN(written, buff, "1.18973e+4932");
24622467

2468+
written = LIBC_NAMESPACE::sprintf(buff, "%Lg", 0xa.aaaaaaaaaaaaaabp-7L);
2469+
ASSERT_STREQ_LEN(written, buff, "0.0833333");
2470+
2471+
#endif // SPECIAL_X86_LONG_DOUBLE
2472+
24632473
// TODO: Uncomment the below tests after long double support is added
24642474
/*
24652475
written = LIBC_NAMESPACE::sprintf(buff, "%Lf", 1e100L);
@@ -2757,6 +2767,15 @@ TEST_F(LlvmLibcSPrintfTest, FloatAutoConv) {
27572767
written = LIBC_NAMESPACE::sprintf(buff, "%.10g", 0x1.0p-1074);
27582768
ASSERT_STREQ_LEN(written, buff, "4.940656458e-324");
27592769

2770+
#if defined(SPECIAL_X86_LONG_DOUBLE)
2771+
2772+
written = LIBC_NAMESPACE::sprintf(buff, "%.60Lg", 0xa.aaaaaaaaaaaaaabp-7L);
2773+
ASSERT_STREQ_LEN(
2774+
written, buff,
2775+
"0.0833333333333333333355920878593448009041821933351457118988037");
2776+
2777+
#endif // SPECIAL_X86_LONG_DOUBLE
2778+
27602779
// Long double precision tests.
27612780
// These are currently commented out because they require long double support
27622781
// that isn't ready yet.

libcxx/include/__algorithm/pstl_backend.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ A PSTL parallel backend is a tag type to which the following functions are assoc
4949
_Comp __comp);
5050
5151
template <class _ExecutionPolicy, class _InIterator, class _OutIterator, class _UnaryOperation>
52-
_OutIterator __pstl_transform(_Backend, _InIterator __first, _InIterator __last, _OutIterator __result, _UnaryOperation __op);
52+
_OutIterator __pstl_transform(_Backend,
53+
_InIterator __first,
54+
_InIterator __last,
55+
_OutIterator __result,
56+
_UnaryOperation __op);
5357
5458
template <class _ExecutionPolicy, class _InIterator1, class _InIterator2, class _OutIterator, class _BinaryOperation>
5559
_OutIterator __pstl_transform(_Backend,

lld/ELF/Arch/X86_64.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "OutputSections.h"
10+
#include "Relocations.h"
1011
#include "Symbols.h"
1112
#include "SyntheticSections.h"
1213
#include "Target.h"
1314
#include "lld/Common/ErrorHandler.h"
1415
#include "llvm/BinaryFormat/ELF.h"
1516
#include "llvm/Support/Endian.h"
17+
#include "llvm/Support/MathExtras.h"
1618

1719
using namespace llvm;
1820
using namespace llvm::object;
@@ -47,6 +49,7 @@ class X86_64 : public TargetInfo {
4749
uint8_t stOther) const override;
4850
bool deleteFallThruJmpInsn(InputSection &is, InputFile *file,
4951
InputSection *nextIS) const override;
52+
bool relaxOnce(int pass) const override;
5053
};
5154
} // namespace
5255

@@ -305,6 +308,43 @@ bool X86_64::deleteFallThruJmpInsn(InputSection &is, InputFile *file,
305308
return true;
306309
}
307310

311+
bool X86_64::relaxOnce(int pass) const {
312+
uint64_t minVA = UINT64_MAX, maxVA = 0;
313+
for (OutputSection *osec : outputSections) {
314+
minVA = std::min(minVA, osec->addr);
315+
maxVA = std::max(maxVA, osec->addr + osec->size);
316+
}
317+
// If the max VA difference is under 2^31, GOT-generating relocations with a 32-bit range cannot overflow.
318+
if (isUInt<31>(maxVA - minVA))
319+
return false;
320+
321+
SmallVector<InputSection *, 0> storage;
322+
bool changed = false;
323+
for (OutputSection *osec : outputSections) {
324+
if (!(osec->flags & SHF_EXECINSTR))
325+
continue;
326+
for (InputSection *sec : getInputSections(*osec, storage)) {
327+
for (Relocation &rel : sec->relocs()) {
328+
if (rel.expr != R_RELAX_GOT_PC)
329+
continue;
330+
331+
uint64_t v = sec->getRelocTargetVA(
332+
sec->file, rel.type, rel.addend,
333+
sec->getOutputSection()->addr + rel.offset, *rel.sym, rel.expr);
334+
if (isInt<32>(v))
335+
continue;
336+
if (rel.sym->auxIdx == 0) {
337+
rel.sym->allocateAux();
338+
addGotEntry(*rel.sym);
339+
changed = true;
340+
}
341+
rel.expr = R_GOT_PC;
342+
}
343+
}
344+
}
345+
return changed;
346+
}
347+
308348
RelExpr X86_64::getRelExpr(RelType type, const Symbol &s,
309349
const uint8_t *loc) const {
310350
switch (type) {
@@ -912,7 +952,8 @@ static void relaxGotNoPic(uint8_t *loc, uint64_t val, uint8_t op,
912952
}
913953

914954
static void relaxGot(uint8_t *loc, const Relocation &rel, uint64_t val) {
915-
checkInt(loc, val, 32, rel);
955+
assert(isInt<32>(val) &&
956+
"GOTPCRELX should not have been relaxed if it overflows");
916957
const uint8_t op = loc[-2];
917958
const uint8_t modRm = loc[-1];
918959

0 commit comments

Comments
 (0)