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 | } |