@@ -124,6 +124,23 @@ void RTDEF(PointerAssociateRemapping)(Descriptor &pointer,
124124 }
125125}
126126
127+ RT_API_ATTRS void *AllocateValidatedPointerPayload (std::size_t byteSize) {
128+ // Add space for a footer to validate during deallocation.
129+ constexpr std::size_t align{sizeof (std::uintptr_t )};
130+ byteSize = ((byteSize / align) + 1 ) * align;
131+ std::size_t total{byteSize + sizeof (std::uintptr_t )};
132+ void *p{std::malloc (total)};
133+ if (p) {
134+ // Fill the footer word with the XOR of the ones' complement of
135+ // the base address, which is a value that would be highly unlikely
136+ // to appear accidentally at the right spot.
137+ std::uintptr_t *footer{
138+ reinterpret_cast <std::uintptr_t *>(static_cast <char *>(p) + byteSize)};
139+ *footer = ~reinterpret_cast <std::uintptr_t >(p);
140+ }
141+ return p;
142+ }
143+
127144int RTDEF (PointerAllocate)(Descriptor &pointer, bool hasStat,
128145 const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
129146 Terminator terminator{sourceFile, sourceLine};
@@ -137,22 +154,12 @@ int RTDEF(PointerAllocate)(Descriptor &pointer, bool hasStat,
137154 elementBytes = pointer.raw ().elem_len = 0 ;
138155 }
139156 std::size_t byteSize{pointer.Elements () * elementBytes};
140- // Add space for a footer to validate during DEALLOCATE.
141- constexpr std::size_t align{sizeof (std::uintptr_t )};
142- byteSize = ((byteSize + align - 1 ) / align) * align;
143- std::size_t total{byteSize + sizeof (std::uintptr_t )};
144- void *p{std::malloc (total)};
157+ void *p{AllocateValidatedPointerPayload (byteSize)};
145158 if (!p) {
146159 return ReturnError (terminator, CFI_ERROR_MEM_ALLOCATION, errMsg, hasStat);
147160 }
148161 pointer.set_base_addr (p);
149162 pointer.SetByteStrides ();
150- // Fill the footer word with the XOR of the ones' complement of
151- // the base address, which is a value that would be highly unlikely
152- // to appear accidentally at the right spot.
153- std::uintptr_t *footer{
154- reinterpret_cast <std::uintptr_t *>(static_cast <char *>(p) + byteSize)};
155- *footer = ~reinterpret_cast <std::uintptr_t >(p);
156163 int stat{StatOk};
157164 if (const DescriptorAddendum * addendum{pointer.Addendum ()}) {
158165 if (const auto *derived{addendum->derivedType ()}) {
@@ -176,6 +183,27 @@ int RTDEF(PointerAllocateSource)(Descriptor &pointer, const Descriptor &source,
176183 return stat;
177184}
178185
186+ static RT_API_ATTRS std::size_t GetByteSize (
187+ const ISO::CFI_cdesc_t &descriptor) {
188+ std::size_t rank{descriptor.rank };
189+ const ISO::CFI_dim_t *dim{descriptor.dim };
190+ std::size_t byteSize{descriptor.elem_len };
191+ for (std::size_t j{0 }; j < rank; ++j) {
192+ byteSize *= dim[j].extent ;
193+ }
194+ return byteSize;
195+ }
196+
197+ bool RT_API_ATTRS ValidatePointerPayload (const ISO::CFI_cdesc_t &desc) {
198+ std::size_t byteSize{GetByteSize (desc)};
199+ constexpr std::size_t align{sizeof (std::uintptr_t )};
200+ byteSize = ((byteSize / align) + 1 ) * align;
201+ const void *p{desc.base_addr };
202+ const std::uintptr_t *footer{reinterpret_cast <const std::uintptr_t *>(
203+ static_cast <const char *>(p) + byteSize)};
204+ return *footer == ~reinterpret_cast <std::uintptr_t >(p);
205+ }
206+
179207int RTDEF (PointerDeallocate)(Descriptor &pointer, bool hasStat,
180208 const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
181209 Terminator terminator{sourceFile, sourceLine};
@@ -185,20 +213,9 @@ int RTDEF(PointerDeallocate)(Descriptor &pointer, bool hasStat,
185213 if (!pointer.IsAllocated ()) {
186214 return ReturnError (terminator, StatBaseNull, errMsg, hasStat);
187215 }
188- if (executionEnvironment.checkPointerDeallocation ) {
189- // Validate the footer. This should fail if the pointer doesn't
190- // span the entire object, or the object was not allocated as a
191- // pointer.
192- std::size_t byteSize{pointer.Elements () * pointer.ElementBytes ()};
193- constexpr std::size_t align{sizeof (std::uintptr_t )};
194- byteSize = ((byteSize + align - 1 ) / align) * align;
195- void *p{pointer.raw ().base_addr };
196- std::uintptr_t *footer{
197- reinterpret_cast <std::uintptr_t *>(static_cast <char *>(p) + byteSize)};
198- if (*footer != ~reinterpret_cast <std::uintptr_t >(p)) {
199- return ReturnError (
200- terminator, StatBadPointerDeallocation, errMsg, hasStat);
201- }
216+ if (executionEnvironment.checkPointerDeallocation &&
217+ !ValidatePointerPayload (pointer.raw ())) {
218+ return ReturnError (terminator, StatBadPointerDeallocation, errMsg, hasStat);
202219 }
203220 return ReturnError (terminator,
204221 pointer.Destroy (/* finalize=*/ true , /* destroyPointers=*/ true , &terminator),
0 commit comments