[flang][runtime] Let FORT_CHECK_POINTER_DEALLOCATION=0 disable runtime … (#84956)

…check

Add an environment variable by which a user can disable the pointer
validation check in DEALLOCATE statement handling. This is not safe, but
it can help make a code work that allocates a pointer with an extended
derived type, associates its target with a pointer to one of its
ancestor types, and then deallocates that pointer.
This commit is contained in:
Peter Klausler
2024-03-13 14:52:25 -07:00
committed by GitHub
parent 5661188c57
commit af964c7e31
5 changed files with 87 additions and 11 deletions

View File

@@ -0,0 +1,57 @@
<!--===- docs/RuntimeEnvironment.md
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
-->
```{contents}
---
local:
---
```
# Environment variables of significance to Fortran execution
A few environment variables are queried by the Fortran runtime support
library.
The following environment variables can affect the behavior of
Fortran programs during execution.
## `DEFAULT_UTF8=1`
Set `DEFAULT_UTF8` to cause formatted external input to assume UTF-8
encoding on input and use UTF-8 encoding on formatted external output.
## `FORT_CONVERT`
Determines data conversions applied to unformatted I/O.
* `NATIVE`: no conversions (default)
* `LITTLE_ENDIAN`: assume input is little-endian; emit little-endian output
* `BIG_ENDIAN`: assume input is big-endian; emit big-endian output
* `SWAP`: reverse endianness (always convert)
## `FORT_CHECK_POINTER_DEALLOCATION`
Fortran requires that a pointer that appears in a `DEALLOCATE` statement
must have been allocated in an `ALLOCATE` statement with the same declared
type.
The runtime support library validates this requirement by checking the
size of the allocated data, and will fail with an error message if
the deallocated pointer is not valid.
Set `FORT_CHECK_POINTER_DEALLOCATION=0` to disable this check.
## `FORT_FMT_RECL`
Set to an integer value to specify the record length for list-directed
and `NAMELIST` output.
The default is 72.
## `NO_STOP_MESSAGE`
Set `NO_STOP_MESSAGE=1` to disable the extra information about
IEEE floating-point exception flags that the Fortran language
standard requires for `STOP` and `ERROR STOP` statements.

View File

@@ -80,6 +80,7 @@ on how to get in touch with us and to learn more about the current status.
Preprocessing
ProcedurePointer
RuntimeDescriptor
RuntimeEnvironment
RuntimeTypeInfo
Semantics
f2018-grammar.md

View File

@@ -123,6 +123,19 @@ void ExecutionEnvironment::Configure(int ac, const char *av[],
}
}
if (auto *x{std::getenv("FORT_CHECK_POINTER_DEALLOCATION")}) {
char *end;
auto n{std::strtol(x, &end, 10)};
if (n >= 0 && n <= 1 && *end == '\0') {
checkPointerDeallocation = n != 0;
} else {
std::fprintf(stderr,
"Fortran runtime: FORT_CHECK_POINTER_DEALLOCATION=%s is invalid; "
"ignored\n",
x);
}
}
// TODO: Set RP/ROUND='PROCESSOR_DEFINED' from environment
}

View File

@@ -48,6 +48,7 @@ struct ExecutionEnvironment {
Convert conversion{Convert::Unknown}; // FORT_CONVERT
bool noStopMessage{false}; // NO_STOP_MESSAGE=1 inhibits "Fortran STOP"
bool defaultUTF8{false}; // DEFAULT_UTF8
bool checkPointerDeallocation{true}; // FORT_CHECK_POINTER_DEALLOCATION
};
extern ExecutionEnvironment executionEnvironment;

View File

@@ -9,6 +9,7 @@
#include "flang/Runtime/pointer.h"
#include "assign-impl.h"
#include "derived.h"
#include "environment.h"
#include "stat.h"
#include "terminator.h"
#include "tools.h"
@@ -184,17 +185,20 @@ int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat,
if (!pointer.IsAllocated()) {
return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
}
// Validate the footer. This should fail if the pointer doesn't
// span the entire object, or the object was not allocated as a
// pointer.
std::size_t byteSize{pointer.Elements() * pointer.ElementBytes()};
constexpr std::size_t align{sizeof(std::uintptr_t)};
byteSize = ((byteSize + align - 1) / align) * align;
void *p{pointer.raw().base_addr};
std::uintptr_t *footer{
reinterpret_cast<std::uintptr_t *>(static_cast<char *>(p) + byteSize)};
if (*footer != ~reinterpret_cast<std::uintptr_t>(p)) {
return ReturnError(terminator, StatBadPointerDeallocation, errMsg, hasStat);
if (executionEnvironment.checkPointerDeallocation) {
// Validate the footer. This should fail if the pointer doesn't
// span the entire object, or the object was not allocated as a
// pointer.
std::size_t byteSize{pointer.Elements() * pointer.ElementBytes()};
constexpr std::size_t align{sizeof(std::uintptr_t)};
byteSize = ((byteSize + align - 1) / align) * align;
void *p{pointer.raw().base_addr};
std::uintptr_t *footer{
reinterpret_cast<std::uintptr_t *>(static_cast<char *>(p) + byteSize)};
if (*footer != ~reinterpret_cast<std::uintptr_t>(p)) {
return ReturnError(
terminator, StatBadPointerDeallocation, errMsg, hasStat);
}
}
return ReturnError(terminator,
pointer.Destroy(/*finalize=*/true, /*destroyPointers=*/true, &terminator),