clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name assign.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -I tools/flang/runtime -I /build/source/flang/runtime -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1675289259 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-02-02-055145-558594-1 -x c++ /build/source/flang/runtime/assign.cpp
| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | #include "flang/Runtime/assign.h" |
| 10 | #include "assign.h" |
| 11 | #include "derived.h" |
| 12 | #include "stat.h" |
| 13 | #include "terminator.h" |
| 14 | #include "type-info.h" |
| 15 | #include "flang/Runtime/descriptor.h" |
| 16 | |
| 17 | namespace Fortran::runtime { |
| 18 | |
| 19 | static void DoScalarDefinedAssignment(const Descriptor &to, |
| 20 | const Descriptor &from, const typeInfo::SpecialBinding &special) { |
| 21 | bool toIsDesc{special.IsArgDescriptor(0)}; |
| 22 | bool fromIsDesc{special.IsArgDescriptor(1)}; |
| 23 | if (toIsDesc) { |
| 24 | if (fromIsDesc) { |
| 25 | auto *p{ |
| 26 | special.GetProc<void (*)(const Descriptor &, const Descriptor &)>()}; |
| 27 | p(to, from); |
| 28 | } else { |
| 29 | auto *p{special.GetProc<void (*)(const Descriptor &, void *)>()}; |
| 30 | p(to, from.raw().base_addr); |
| 31 | } |
| 32 | } else { |
| 33 | if (fromIsDesc) { |
| 34 | auto *p{special.GetProc<void (*)(void *, const Descriptor &)>()}; |
| 35 | p(to.raw().base_addr, from); |
| 36 | } else { |
| 37 | auto *p{special.GetProc<void (*)(void *, void *)>()}; |
| 38 | p(to.raw().base_addr, from.raw().base_addr); |
| 39 | } |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | static void DoElementalDefinedAssignment(const Descriptor &to, |
| 44 | const Descriptor &from, const typeInfo::SpecialBinding &special, |
| 45 | std::size_t toElements, SubscriptValue toAt[], SubscriptValue fromAt[]) { |
| 46 | StaticDescriptor<maxRank, true, 8 > statDesc[2]; |
| 47 | Descriptor &toElementDesc{statDesc[0].descriptor()}; |
| 48 | Descriptor &fromElementDesc{statDesc[1].descriptor()}; |
| 49 | toElementDesc = to; |
| 50 | toElementDesc.raw().attribute = CFI_attribute_pointer; |
| 51 | toElementDesc.raw().rank = 0; |
| 52 | fromElementDesc = from; |
| 53 | fromElementDesc.raw().attribute = CFI_attribute_pointer; |
| 54 | fromElementDesc.raw().rank = 0; |
| 55 | for (std::size_t j{0}; j < toElements; |
| 56 | ++j, to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 57 | toElementDesc.set_base_addr(to.Element<char>(toAt)); |
| 58 | fromElementDesc.set_base_addr(from.Element<char>(fromAt)); |
| 59 | DoScalarDefinedAssignment(toElementDesc, fromElementDesc, special); |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | static void Assign(Descriptor &to, const Descriptor &from, |
| 71 | Terminator &terminator, bool skipRealloc = false) { |
| 72 | DescriptorAddendum *toAddendum{to.Addendum()}; |
| 73 | const typeInfo::DerivedType *toDerived{ |
| 74 | toAddendum ? toAddendum->derivedType() : nullptr}; |
| |
| 75 | const DescriptorAddendum *fromAddendum{from.Addendum()}; |
| 76 | const typeInfo::DerivedType *fromDerived{ |
| 77 | fromAddendum ? fromAddendum->derivedType() : nullptr}; |
| |
| 78 | bool wasJustAllocated{false}; |
| 79 | if (to.IsAllocatable()) { |
| |
| 80 | std::size_t lenParms{fromDerived ? fromDerived->LenParameters() : 0}; |
| 81 | if (to.IsAllocated() && !skipRealloc) { |
| 82 | |
| 83 | |
| 84 | |
| 85 | bool deallocate{false}; |
| 86 | if (to.type() != from.type()) { |
| 87 | deallocate = true; |
| 88 | } else if (toDerived != fromDerived) { |
| 89 | deallocate = true; |
| 90 | } else { |
| 91 | if (toAddendum) { |
| 92 | |
| 93 | for (std::size_t j{0}; j < lenParms; ++j) { |
| 94 | if (toAddendum->LenParameterValue(j) != |
| 95 | fromAddendum->LenParameterValue(j)) { |
| 96 | deallocate = true; |
| 97 | break; |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | if (from.rank() > 0) { |
| 102 | |
| 103 | int rank{to.rank()}; |
| 104 | for (int j{0}; j < rank; ++j) { |
| 105 | if (to.GetDimension(j).Extent() != from.GetDimension(j).Extent()) { |
| 106 | deallocate = true; |
| 107 | break; |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | if (deallocate) { |
| 113 | to.Destroy(true ); |
| 114 | } |
| 115 | } else if (to.rank() != from.rank()) { |
| 116 | terminator.Crash("Assign: mismatched ranks (%d != %d) in assignment to " |
| 117 | "unallocated allocatable", |
| 118 | to.rank(), from.rank()); |
| 119 | } |
| 120 | if (!to.IsAllocated()) { |
| 121 | to.raw().type = from.raw().type; |
| 122 | to.raw().elem_len = from.ElementBytes(); |
| 123 | if (toAddendum) { |
| 124 | toDerived = fromDerived; |
| 125 | toAddendum->set_derivedType(toDerived); |
| 126 | for (std::size_t j{0}; j < lenParms; ++j) { |
| 127 | toAddendum->SetLenParameterValue( |
| 128 | j, fromAddendum->LenParameterValue(j)); |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | int rank{from.rank()}; |
| 133 | auto stride{static_cast<SubscriptValue>(to.ElementBytes())}; |
| 134 | for (int j{0}; j < rank; ++j) { |
| 135 | auto &toDim{to.GetDimension(j)}; |
| 136 | const auto &fromDim{from.GetDimension(j)}; |
| 137 | toDim.SetBounds(fromDim.LowerBound(), fromDim.UpperBound()); |
| 138 | toDim.SetByteStride(stride); |
| 139 | stride *= toDim.Extent(); |
| 140 | } |
| 141 | ReturnError(terminator, to.Allocate()); |
| 142 | if (fromDerived && !fromDerived->noInitializationNeeded()) { |
| 143 | ReturnError(terminator, Initialize(to, *toDerived, terminator)); |
| 144 | } |
| 145 | wasJustAllocated = true; |
| 146 | } |
| 147 | } |
| 148 | SubscriptValue toAt[maxRank]; |
| 149 | to.GetLowerBounds(toAt); |
| 150 | |
| 151 | |
| 152 | |
| 153 | SubscriptValue fromAt[maxRank]; |
| 154 | from.GetLowerBounds(fromAt); |
| 155 | std::size_t toElements{to.Elements()}; |
| 156 | if (from.rank() > 0 && toElements != from.Elements()) { |
| 4 | | Assuming the condition is false | |
|
| 157 | terminator.Crash("Assign: mismatching element counts in array assignment " |
| 158 | "(to %zd, from %zd)", |
| 159 | toElements, from.Elements()); |
| 160 | } |
| 161 | if (to.type() != from.type()) { |
| |
| 162 | terminator.Crash("Assign: mismatching types (to code %d != from code %d)", |
| 163 | to.type().raw(), from.type().raw()); |
| 164 | } |
| 165 | std::size_t elementBytes{to.ElementBytes()}; |
| 166 | if (elementBytes != from.ElementBytes()) { |
| 6 | | Assuming the condition is false | |
|
| |
| 167 | terminator.Crash( |
| 168 | "Assign: mismatching element sizes (to %zd bytes != from %zd bytes)", |
| 169 | elementBytes, from.ElementBytes()); |
| 170 | } |
| 171 | if (toDerived) { |
| 8 | | Assuming 'toDerived' is non-null | |
|
| |
| 172 | |
| 173 | if (to.rank() == 0) { |
| 10 | | Assuming the condition is false | |
|
| |
| 174 | if (const auto *special{toDerived->FindSpecialBinding( |
| 175 | typeInfo::SpecialBinding::Which::ScalarAssignment)}) { |
| 176 | return DoScalarDefinedAssignment(to, from, *special); |
| 177 | } |
| 178 | } |
| 179 | if (const auto *special{toDerived->FindSpecialBinding( |
| 180 | typeInfo::SpecialBinding::Which::ElementalAssignment)}) { |
| 181 | return DoElementalDefinedAssignment( |
| 182 | to, from, *special, toElements, toAt, fromAt); |
| 183 | } |
| 184 | |
| 185 | |
| 186 | |
| 187 | if (!wasJustAllocated && !toDerived->noFinalizationNeeded()) { |
| 12 | | Assuming the condition is false | |
|
| |
| 188 | Finalize(to, *toDerived); |
| 189 | } |
| 190 | |
| 191 | const Descriptor &componentDesc{toDerived->component()}; |
| 192 | std::size_t numComponents{componentDesc.Elements()}; |
| 193 | for (std::size_t k{0}; k < numComponents; ++k) { |
| 14 | | Assuming 'k' is >= 'numComponents' | |
|
| 15 | | Loop condition is false. Execution continues on line 259 | |
|
| 194 | const auto &comp{ |
| 195 | *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>( |
| 196 | k)}; |
| 197 | switch (comp.genre()) { |
| 198 | case typeInfo::Component::Genre::Data: |
| 199 | if (comp.category() == TypeCategory::Derived) { |
| 200 | StaticDescriptor<maxRank, true, 10 > statDesc[2]; |
| 201 | Descriptor &toCompDesc{statDesc[0].descriptor()}; |
| 202 | Descriptor &fromCompDesc{statDesc[1].descriptor()}; |
| 203 | for (std::size_t j{0}; j < toElements; ++j, |
| 204 | to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 205 | comp.CreatePointerDescriptor(toCompDesc, to, terminator, toAt); |
| 206 | comp.CreatePointerDescriptor( |
| 207 | fromCompDesc, from, terminator, fromAt); |
| 208 | Assign(toCompDesc, fromCompDesc, terminator, false); |
| 209 | } |
| 210 | } else { |
| 211 | std::size_t componentByteSize{comp.SizeInBytes(to)}; |
| 212 | for (std::size_t j{0}; j < toElements; ++j, |
| 213 | to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 214 | std::memmove(to.Element<char>(toAt) + comp.offset(), |
| 215 | from.Element<const char>(fromAt) + comp.offset(), |
| 216 | componentByteSize); |
| 217 | } |
| 218 | } |
| 219 | break; |
| 220 | case typeInfo::Component::Genre::Pointer: { |
| 221 | std::size_t componentByteSize{comp.SizeInBytes(to)}; |
| 222 | for (std::size_t j{0}; j < toElements; ++j, |
| 223 | to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 224 | std::memmove(to.Element<char>(toAt) + comp.offset(), |
| 225 | from.Element<const char>(fromAt) + comp.offset(), |
| 226 | componentByteSize); |
| 227 | } |
| 228 | } break; |
| 229 | case typeInfo::Component::Genre::Allocatable: |
| 230 | case typeInfo::Component::Genre::Automatic: |
| 231 | for (std::size_t j{0}; j < toElements; ++j, |
| 232 | to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 233 | auto *toDesc{reinterpret_cast<Descriptor *>( |
| 234 | to.Element<char>(toAt) + comp.offset())}; |
| 235 | const auto *fromDesc{reinterpret_cast<const Descriptor *>( |
| 236 | from.Element<char>(fromAt) + comp.offset())}; |
| 237 | if (toDesc->IsAllocatable()) { |
| 238 | if (toDesc->IsAllocated()) { |
| 239 | |
| 240 | |
| 241 | |
| 242 | |
| 243 | |
| 244 | |
| 245 | |
| 246 | |
| 247 | toDesc->Destroy(false ); |
| 248 | } |
| 249 | if (!fromDesc->IsAllocated()) { |
| 250 | continue; |
| 251 | } |
| 252 | } |
| 253 | Assign(*toDesc, *fromDesc, terminator, false); |
| 254 | } |
| 255 | break; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | const Descriptor &procPtrDesc{toDerived->procPtr()}; |
| 260 | std::size_t numProcPtrs{procPtrDesc.Elements()}; |
| 261 | for (std::size_t k{0}; k < numProcPtrs; ++k) { |
| 16 | | Assuming 'k' is < 'numProcPtrs' | |
|
| 17 | | Loop condition is true. Entering loop body | |
|
| 262 | const auto &procPtr{ |
| 18 | | Dereference of null pointer |
|
| 263 | *procPtrDesc.ZeroBasedIndexedElement<typeInfo::ProcPtrComponent>(k)}; |
| 264 | for (std::size_t j{0}; j < toElements; ++j, to.IncrementSubscripts(toAt), |
| 265 | from.IncrementSubscripts(fromAt)) { |
| 266 | std::memmove(to.Element<char>(toAt) + procPtr.offset, |
| 267 | from.Element<const char>(fromAt) + procPtr.offset, |
| 268 | sizeof(typeInfo::ProcedurePointer)); |
| 269 | } |
| 270 | } |
| 271 | } else { |
| 272 | if (to.rank() == from.rank() && to.IsContiguous() && from.IsContiguous()) { |
| 273 | |
| 274 | std::memmove( |
| 275 | to.raw().base_addr, from.raw().base_addr, toElements * elementBytes); |
| 276 | } else { |
| 277 | for (std::size_t n{toElements}; n-- > 0; |
| 278 | to.IncrementSubscripts(toAt), from.IncrementSubscripts(fromAt)) { |
| 279 | std::memmove(to.Element<char>(toAt), from.Element<const char>(fromAt), |
| 280 | elementBytes); |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | void DoFromSourceAssign( |
| 287 | Descriptor &alloc, const Descriptor &source, Terminator &terminator) { |
| 288 | if (alloc.rank() > 0 && source.rank() == 0) { |
| 289 | |
| 290 | DescriptorAddendum *allocAddendum{alloc.Addendum()}; |
| 291 | const typeInfo::DerivedType *allocDerived{ |
| 292 | allocAddendum ? allocAddendum->derivedType() : nullptr}; |
| 293 | SubscriptValue allocAt[maxRank]; |
| 294 | alloc.GetLowerBounds(allocAt); |
| 295 | if (allocDerived) { |
| 296 | for (std::size_t n{alloc.Elements()}; n-- > 0; |
| 297 | alloc.IncrementSubscripts(allocAt)) { |
| 298 | Descriptor allocElement{*Descriptor::Create(*allocDerived, |
| 299 | reinterpret_cast<void *>(alloc.Element<char>(allocAt)), 0)}; |
| 300 | Assign(allocElement, source, terminator, true); |
| 301 | } |
| 302 | } else { |
| 303 | for (std::size_t n{alloc.Elements()}; n-- > 0; |
| 304 | alloc.IncrementSubscripts(allocAt)) { |
| 305 | std::memmove(alloc.Element<char>(allocAt), source.raw().base_addr, |
| 306 | alloc.ElementBytes()); |
| 307 | } |
| 308 | } |
| 309 | } else { |
| 310 | Assign(alloc, source, terminator, true); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | extern "C" { |
| 315 | void RTNAME(Assign)(Descriptor &to, const Descriptor &from, |
| 316 | const char *sourceFile, int sourceLine) { |
| 317 | Terminator terminator{sourceFile, sourceLine}; |
| 318 | Assign(to, from, terminator); |
| 319 | } |
| 320 | |
| 321 | } |
| 322 | } |