2021-07-16 10:42:17 -07:00
|
|
|
//===-- runtime/pointer.cpp -----------------------------------------------===//
|
|
|
|
|
//
|
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2021-09-01 16:00:53 -07:00
|
|
|
#include "flang/Runtime/pointer.h"
|
2023-02-01 15:25:54 -08:00
|
|
|
#include "assign-impl.h"
|
2021-07-19 11:53:20 -07:00
|
|
|
#include "derived.h"
|
2024-03-13 14:52:25 -07:00
|
|
|
#include "environment.h"
|
2021-07-16 10:42:17 -07:00
|
|
|
#include "stat.h"
|
|
|
|
|
#include "terminator.h"
|
|
|
|
|
#include "tools.h"
|
2021-07-19 11:53:20 -07:00
|
|
|
#include "type-info.h"
|
2021-07-16 10:42:17 -07:00
|
|
|
|
|
|
|
|
namespace Fortran::runtime {
|
|
|
|
|
extern "C" {
|
2023-12-28 13:50:43 -08:00
|
|
|
RT_EXT_API_GROUP_BEGIN
|
2021-07-16 10:42:17 -07:00
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerNullifyIntrinsic)(Descriptor &pointer, TypeCategory category,
|
2021-07-16 10:42:17 -07:00
|
|
|
int kind, int rank, int corank) {
|
|
|
|
|
INTERNAL_CHECK(corank == 0);
|
|
|
|
|
pointer.Establish(TypeCode{category, kind},
|
|
|
|
|
Descriptor::BytesFor(category, kind), nullptr, rank, nullptr,
|
|
|
|
|
CFI_attribute_pointer);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerNullifyCharacter)(Descriptor &pointer, SubscriptValue length,
|
2021-07-16 10:42:17 -07:00
|
|
|
int kind, int rank, int corank) {
|
|
|
|
|
INTERNAL_CHECK(corank == 0);
|
|
|
|
|
pointer.Establish(
|
|
|
|
|
kind, length, nullptr, rank, nullptr, CFI_attribute_pointer);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerNullifyDerived)(Descriptor &pointer,
|
2021-07-16 10:42:17 -07:00
|
|
|
const typeInfo::DerivedType &derivedType, int rank, int corank) {
|
|
|
|
|
INTERNAL_CHECK(corank == 0);
|
|
|
|
|
pointer.Establish(derivedType, nullptr, rank, nullptr, CFI_attribute_pointer);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerSetBounds)(Descriptor &pointer, int zeroBasedDim,
|
2021-07-16 10:42:17 -07:00
|
|
|
SubscriptValue lower, SubscriptValue upper) {
|
|
|
|
|
INTERNAL_CHECK(zeroBasedDim >= 0 && zeroBasedDim < pointer.rank());
|
|
|
|
|
pointer.GetDimension(zeroBasedDim).SetBounds(lower, upper);
|
|
|
|
|
// The byte strides are computed when the pointer is allocated.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: PointerSetCoBounds
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerSetDerivedLength)(
|
2021-07-16 10:42:17 -07:00
|
|
|
Descriptor &pointer, int which, SubscriptValue x) {
|
|
|
|
|
DescriptorAddendum *addendum{pointer.Addendum()};
|
|
|
|
|
INTERNAL_CHECK(addendum != nullptr);
|
|
|
|
|
addendum->SetLenParameterValue(which, x);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerApplyMold)(
|
2023-02-02 10:23:06 +01:00
|
|
|
Descriptor &pointer, const Descriptor &mold, int rank) {
|
2023-10-17 08:20:38 -07:00
|
|
|
pointer.ApplyMold(mold, rank);
|
2021-07-16 10:42:17 -07:00
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerAssociateScalar)(Descriptor &pointer, void *target) {
|
2021-07-16 10:42:17 -07:00
|
|
|
pointer.set_base_addr(target);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerAssociate)(Descriptor &pointer, const Descriptor &target) {
|
2021-07-16 10:42:17 -07:00
|
|
|
pointer = target;
|
|
|
|
|
pointer.raw().attribute = CFI_attribute_pointer;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerAssociateLowerBounds)(Descriptor &pointer,
|
2021-07-16 10:42:17 -07:00
|
|
|
const Descriptor &target, const Descriptor &lowerBounds) {
|
|
|
|
|
pointer = target;
|
|
|
|
|
pointer.raw().attribute = CFI_attribute_pointer;
|
|
|
|
|
int rank{pointer.rank()};
|
|
|
|
|
Terminator terminator{__FILE__, __LINE__};
|
|
|
|
|
std::size_t boundElementBytes{lowerBounds.ElementBytes()};
|
|
|
|
|
for (int j{0}; j < rank; ++j) {
|
2022-03-09 13:43:54 -08:00
|
|
|
Dimension &dim{pointer.GetDimension(j)};
|
|
|
|
|
dim.SetLowerBound(dim.Extent() == 0
|
|
|
|
|
? 1
|
|
|
|
|
: GetInt64(lowerBounds.ZeroBasedIndexedElement<const char>(j),
|
|
|
|
|
boundElementBytes, terminator));
|
2021-07-16 10:42:17 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
void RTDEF(PointerAssociateRemapping)(Descriptor &pointer,
|
2021-07-16 10:42:17 -07:00
|
|
|
const Descriptor &target, const Descriptor &bounds, const char *sourceFile,
|
|
|
|
|
int sourceLine) {
|
|
|
|
|
pointer = target;
|
|
|
|
|
pointer.raw().attribute = CFI_attribute_pointer;
|
|
|
|
|
Terminator terminator{sourceFile, sourceLine};
|
|
|
|
|
SubscriptValue byteStride{/*captured from first dimension*/};
|
|
|
|
|
std::size_t boundElementBytes{bounds.ElementBytes()};
|
2023-02-28 14:01:10 +01:00
|
|
|
std::size_t boundsRank{
|
|
|
|
|
static_cast<std::size_t>(bounds.GetDimension(1).Extent())};
|
|
|
|
|
pointer.raw().rank = boundsRank;
|
2023-02-28 14:26:43 +01:00
|
|
|
for (unsigned j{0}; j < boundsRank; ++j) {
|
2021-07-16 10:42:17 -07:00
|
|
|
auto &dim{pointer.GetDimension(j)};
|
|
|
|
|
dim.SetBounds(GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j),
|
|
|
|
|
boundElementBytes, terminator),
|
|
|
|
|
GetInt64(bounds.ZeroBasedIndexedElement<const char>(2 * j + 1),
|
|
|
|
|
boundElementBytes, terminator));
|
|
|
|
|
if (j == 0) {
|
2023-02-08 17:55:38 +01:00
|
|
|
byteStride = dim.ByteStride() * dim.Extent();
|
2021-07-16 10:42:17 -07:00
|
|
|
} else {
|
|
|
|
|
dim.SetByteStride(byteStride);
|
|
|
|
|
byteStride *= dim.Extent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (pointer.Elements() > target.Elements()) {
|
|
|
|
|
terminator.Crash("PointerAssociateRemapping: too many elements in remapped "
|
|
|
|
|
"pointer (%zd > %zd)",
|
|
|
|
|
pointer.Elements(), target.Elements());
|
|
|
|
|
}
|
2023-02-20 09:43:57 +01:00
|
|
|
if (auto *pointerAddendum{pointer.Addendum()}) {
|
|
|
|
|
if (const auto *targetAddendum{target.Addendum()}) {
|
|
|
|
|
if (const auto *derived{targetAddendum->derivedType()}) {
|
|
|
|
|
pointerAddendum->set_derivedType(derived);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-16 10:42:17 -07:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 10:46:30 -07:00
|
|
|
RT_API_ATTRS void *AllocateValidatedPointerPayload(std::size_t byteSize) {
|
|
|
|
|
// Add space for a footer to validate during deallocation.
|
|
|
|
|
constexpr std::size_t align{sizeof(std::uintptr_t)};
|
2024-06-28 11:32:09 -07:00
|
|
|
byteSize = ((byteSize + align - 1) / align) * align;
|
2024-06-24 10:46:30 -07:00
|
|
|
std::size_t total{byteSize + sizeof(std::uintptr_t)};
|
|
|
|
|
void *p{std::malloc(total)};
|
|
|
|
|
if (p) {
|
|
|
|
|
// Fill the footer word with the XOR of the ones' complement of
|
|
|
|
|
// the base address, which is a value that would be highly unlikely
|
|
|
|
|
// to appear accidentally at the right spot.
|
|
|
|
|
std::uintptr_t *footer{
|
|
|
|
|
reinterpret_cast<std::uintptr_t *>(static_cast<char *>(p) + byteSize)};
|
|
|
|
|
*footer = ~reinterpret_cast<std::uintptr_t>(p);
|
|
|
|
|
}
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
int RTDEF(PointerAllocate)(Descriptor &pointer, bool hasStat,
|
2021-07-16 10:42:17 -07:00
|
|
|
const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
|
|
|
|
|
Terminator terminator{sourceFile, sourceLine};
|
|
|
|
|
if (!pointer.IsPointer()) {
|
|
|
|
|
return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
|
|
|
|
|
}
|
2024-01-25 14:44:09 -08:00
|
|
|
std::size_t elementBytes{pointer.ElementBytes()};
|
|
|
|
|
if (static_cast<std::int64_t>(elementBytes) < 0) {
|
|
|
|
|
// F'2023 7.4.4.2 p5: "If the character length parameter value evaluates
|
|
|
|
|
// to a negative value, the length of character entities declared is zero."
|
|
|
|
|
elementBytes = pointer.raw().elem_len = 0;
|
|
|
|
|
}
|
|
|
|
|
std::size_t byteSize{pointer.Elements() * elementBytes};
|
2024-06-24 10:46:30 -07:00
|
|
|
void *p{AllocateValidatedPointerPayload(byteSize)};
|
2024-01-25 14:44:09 -08:00
|
|
|
if (!p) {
|
|
|
|
|
return ReturnError(terminator, CFI_ERROR_MEM_ALLOCATION, errMsg, hasStat);
|
|
|
|
|
}
|
|
|
|
|
pointer.set_base_addr(p);
|
|
|
|
|
pointer.SetByteStrides();
|
|
|
|
|
int stat{StatOk};
|
|
|
|
|
if (const DescriptorAddendum * addendum{pointer.Addendum()}) {
|
|
|
|
|
if (const auto *derived{addendum->derivedType()}) {
|
|
|
|
|
if (!derived->noInitializationNeeded()) {
|
|
|
|
|
stat = Initialize(pointer, *derived, terminator, hasStat, errMsg);
|
2021-07-19 11:53:20 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-25 14:44:09 -08:00
|
|
|
return ReturnError(terminator, stat, errMsg, hasStat);
|
2021-07-16 10:42:17 -07:00
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
int RTDEF(PointerAllocateSource)(Descriptor &pointer, const Descriptor &source,
|
2023-01-13 20:40:51 +08:00
|
|
|
bool hasStat, const Descriptor *errMsg, const char *sourceFile,
|
|
|
|
|
int sourceLine) {
|
|
|
|
|
int stat{RTNAME(PointerAllocate)(
|
|
|
|
|
pointer, hasStat, errMsg, sourceFile, sourceLine)};
|
|
|
|
|
if (stat == StatOk) {
|
|
|
|
|
Terminator terminator{sourceFile, sourceLine};
|
2023-02-01 21:09:02 +08:00
|
|
|
DoFromSourceAssign(pointer, source, terminator);
|
2023-01-13 20:40:51 +08:00
|
|
|
}
|
|
|
|
|
return stat;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-24 10:46:30 -07:00
|
|
|
static RT_API_ATTRS std::size_t GetByteSize(
|
|
|
|
|
const ISO::CFI_cdesc_t &descriptor) {
|
|
|
|
|
std::size_t rank{descriptor.rank};
|
|
|
|
|
const ISO::CFI_dim_t *dim{descriptor.dim};
|
|
|
|
|
std::size_t byteSize{descriptor.elem_len};
|
|
|
|
|
for (std::size_t j{0}; j < rank; ++j) {
|
|
|
|
|
byteSize *= dim[j].extent;
|
|
|
|
|
}
|
|
|
|
|
return byteSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RT_API_ATTRS ValidatePointerPayload(const ISO::CFI_cdesc_t &desc) {
|
|
|
|
|
std::size_t byteSize{GetByteSize(desc)};
|
|
|
|
|
constexpr std::size_t align{sizeof(std::uintptr_t)};
|
2024-06-28 11:32:09 -07:00
|
|
|
byteSize = ((byteSize + align - 1) / align) * align;
|
2024-06-24 10:46:30 -07:00
|
|
|
const void *p{desc.base_addr};
|
|
|
|
|
const std::uintptr_t *footer{reinterpret_cast<const std::uintptr_t *>(
|
|
|
|
|
static_cast<const char *>(p) + byteSize)};
|
|
|
|
|
return *footer == ~reinterpret_cast<std::uintptr_t>(p);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat,
|
2021-07-16 10:42:17 -07:00
|
|
|
const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
|
|
|
|
|
Terminator terminator{sourceFile, sourceLine};
|
|
|
|
|
if (!pointer.IsPointer()) {
|
|
|
|
|
return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
|
|
|
|
|
}
|
|
|
|
|
if (!pointer.IsAllocated()) {
|
|
|
|
|
return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
|
|
|
|
|
}
|
2024-06-24 10:46:30 -07:00
|
|
|
if (executionEnvironment.checkPointerDeallocation &&
|
|
|
|
|
!ValidatePointerPayload(pointer.raw())) {
|
|
|
|
|
return ReturnError(terminator, StatBadPointerDeallocation, errMsg, hasStat);
|
2024-01-25 14:44:09 -08:00
|
|
|
}
|
2023-07-29 08:34:14 -07:00
|
|
|
return ReturnError(terminator,
|
|
|
|
|
pointer.Destroy(/*finalize=*/true, /*destroyPointers=*/true, &terminator),
|
|
|
|
|
errMsg, hasStat);
|
2021-07-16 10:42:17 -07:00
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
int RTDEF(PointerDeallocatePolymorphic)(Descriptor &pointer,
|
2023-01-12 11:12:00 +01:00
|
|
|
const typeInfo::DerivedType *derivedType, bool hasStat,
|
|
|
|
|
const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
|
|
|
|
|
int stat{RTNAME(PointerDeallocate)(
|
|
|
|
|
pointer, hasStat, errMsg, sourceFile, sourceLine)};
|
|
|
|
|
if (stat == StatOk) {
|
2023-10-17 08:20:38 -07:00
|
|
|
if (DescriptorAddendum * addendum{pointer.Addendum()}) {
|
2023-01-18 18:52:44 +01:00
|
|
|
addendum->set_derivedType(derivedType);
|
2023-10-17 08:20:38 -07:00
|
|
|
pointer.raw().type = derivedType ? CFI_type_struct : CFI_type_other;
|
2023-01-18 18:52:44 +01:00
|
|
|
} else {
|
|
|
|
|
// Unlimited polymorphic descriptors initialized with
|
|
|
|
|
// PointerNullifyIntrinsic do not have an addendum. Make sure the
|
|
|
|
|
// derivedType is null in that case.
|
|
|
|
|
INTERNAL_CHECK(!derivedType);
|
2023-10-17 08:20:38 -07:00
|
|
|
pointer.raw().type = CFI_type_other;
|
2023-01-18 18:52:44 +01:00
|
|
|
}
|
2023-01-12 11:12:00 +01:00
|
|
|
}
|
|
|
|
|
return stat;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
bool RTDEF(PointerIsAssociated)(const Descriptor &pointer) {
|
2021-07-16 10:42:17 -07:00
|
|
|
return pointer.raw().base_addr != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
bool RTDEF(PointerIsAssociatedWith)(
|
2022-03-03 10:11:19 +01:00
|
|
|
const Descriptor &pointer, const Descriptor *target) {
|
|
|
|
|
if (!target) {
|
|
|
|
|
return pointer.raw().base_addr != nullptr;
|
|
|
|
|
}
|
2023-03-09 16:05:57 +01:00
|
|
|
if (!target->raw().base_addr ||
|
|
|
|
|
(target->raw().type != CFI_type_struct && target->ElementBytes() == 0)) {
|
2022-03-03 10:11:19 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2021-07-16 10:42:17 -07:00
|
|
|
int rank{pointer.rank()};
|
2022-03-03 10:11:19 +01:00
|
|
|
if (pointer.raw().base_addr != target->raw().base_addr ||
|
|
|
|
|
pointer.ElementBytes() != target->ElementBytes() ||
|
|
|
|
|
rank != target->rank()) {
|
2021-07-16 10:42:17 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (int j{0}; j < rank; ++j) {
|
|
|
|
|
const Dimension &pDim{pointer.GetDimension(j)};
|
2022-03-03 10:11:19 +01:00
|
|
|
const Dimension &tDim{target->GetDimension(j)};
|
2022-06-13 08:56:09 -07:00
|
|
|
auto pExtent{pDim.Extent()};
|
|
|
|
|
if (pExtent == 0 || pExtent != tDim.Extent() ||
|
|
|
|
|
(pExtent != 1 && pDim.ByteStride() != tDim.ByteStride())) {
|
2021-07-16 10:42:17 -07:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-13 20:40:51 +08:00
|
|
|
// TODO: PointerCheckLengthParameter
|
2021-07-16 10:42:17 -07:00
|
|
|
|
2023-12-28 13:50:43 -08:00
|
|
|
RT_EXT_API_GROUP_END
|
2021-07-16 10:42:17 -07:00
|
|
|
} // extern "C"
|
|
|
|
|
} // namespace Fortran::runtime
|