Skip to content

Commit 660cdac

Browse files
authored
[flang] Fixed write past allocated descriptor in PointerAssociateRemapping. (#127000)
The pointer descriptor might be smaller than the target descriptor, so `operator=` would write beyound the pointer descriptor.
1 parent 9a63a2c commit 660cdac

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

flang/runtime/pointer.cpp

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,18 @@ void RTDEF(PointerAssociateLowerBounds)(Descriptor &pointer,
8989
void RTDEF(PointerAssociateRemapping)(Descriptor &pointer,
9090
const Descriptor &target, const Descriptor &bounds, const char *sourceFile,
9191
int sourceLine) {
92-
pointer = target;
93-
pointer.raw().attribute = CFI_attribute_pointer;
9492
Terminator terminator{sourceFile, sourceLine};
9593
SubscriptValue byteStride{/*captured from first dimension*/};
9694
std::size_t boundElementBytes{bounds.ElementBytes()};
9795
std::size_t boundsRank{
9896
static_cast<std::size_t>(bounds.GetDimension(1).Extent())};
99-
pointer.raw().rank = boundsRank;
97+
// We cannot just assign target into pointer descriptor, because
98+
// the ranks may mismatch. Use target as a mold for initializing
99+
// the pointer descriptor.
100+
INTERNAL_CHECK(static_cast<std::size_t>(pointer.rank()) == boundsRank);
101+
pointer.ApplyMold(target, boundsRank);
102+
pointer.set_base_addr(target.raw().base_addr);
103+
pointer.raw().attribute = CFI_attribute_pointer;
100104
for (unsigned j{0}; j < boundsRank; ++j) {
101105
auto &dim{pointer.GetDimension(j)};
102106
dim.SetBounds(GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j),
@@ -115,13 +119,6 @@ void RTDEF(PointerAssociateRemapping)(Descriptor &pointer,
115119
"pointer (%zd > %zd)",
116120
pointer.Elements(), target.Elements());
117121
}
118-
if (auto *pointerAddendum{pointer.Addendum()}) {
119-
if (const auto *targetAddendum{target.Addendum()}) {
120-
if (const auto *derived{targetAddendum->derivedType()}) {
121-
pointerAddendum->set_derivedType(derived);
122-
}
123-
}
124-
}
125122
}
126123

127124
RT_API_ATTRS void *AllocateValidatedPointerPayload(std::size_t byteSize) {

flang/unittests/Runtime/Pointer.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,47 @@ TEST(Pointer, AllocateSourceZeroSize) {
105105
EXPECT_EQ(p->GetDimension(0).UpperBound(), 0);
106106
p->Destroy();
107107
}
108+
109+
TEST(Pointer, PointerAssociateRemapping) {
110+
using Fortran::common::TypeCategory;
111+
// REAL(4), POINTER :: p(:)
112+
StaticDescriptor<Fortran::common::maxRank, true> staticDesc;
113+
auto p{staticDesc.descriptor()};
114+
SubscriptValue extent[1]{1};
115+
p.Establish(TypeCode{Fortran::common::TypeCategory::Real, 4}, 4, nullptr, 1,
116+
extent, CFI_attribute_pointer);
117+
std::size_t descSize{p.SizeInBytes()};
118+
EXPECT_LE(descSize, staticDesc.byteSize);
119+
// REAL(4), CONTIGUOUS, POINTER :: t(:,:,:)
120+
auto t{Descriptor::Create(TypeCode{Fortran::common::TypeCategory::Real, 4}, 4,
121+
nullptr, 3, nullptr, CFI_attribute_pointer)};
122+
RTNAME(PointerSetBounds)(*t, 0, 1, 1);
123+
RTNAME(PointerSetBounds)(*t, 1, 1, 1);
124+
RTNAME(PointerSetBounds)(*t, 2, 1, 1);
125+
RTNAME(PointerAllocate)(
126+
*t, /*hasStat=*/false, /*errMsg=*/nullptr, __FILE__, __LINE__);
127+
EXPECT_TRUE(RTNAME(PointerIsAssociated)(*t));
128+
// INTEGER(4) :: b(2,1) = [[1,1]]
129+
auto b{MakeArray<TypeCategory::Integer, 4>(
130+
std::vector<int>{2, 1}, std::vector<std::int32_t>{1, 1})};
131+
// p(1:1) => t
132+
RTNAME(PointerAssociateRemapping)(p, *t, *b, __FILE__, __LINE__);
133+
EXPECT_TRUE(RTNAME(PointerIsAssociated)(p));
134+
EXPECT_EQ(p.rank(), 1);
135+
EXPECT_EQ(p.Elements(), 1u);
136+
137+
// Verify that the memory past the p's descriptor is not affected.
138+
const char *addr = reinterpret_cast<const char *>(&staticDesc);
139+
const char *ptr = addr + descSize;
140+
const char *end = addr + staticDesc.byteSize;
141+
while (ptr != end) {
142+
if (*ptr != '\0') {
143+
std::fprintf(stderr, "byte %zd after pointer descriptor was written\n",
144+
ptr - addr);
145+
EXPECT_EQ(*ptr, '\0');
146+
break;
147+
}
148+
++ptr;
149+
}
150+
p.Destroy();
151+
}

0 commit comments

Comments
 (0)