[libcxx-commits] [PATCH] D151953: [libc++] Fix std::copy and std::move for ranges with potentially overlapping tail padding

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 2 11:59:27 PDT 2023


ldionne requested changes to this revision.
ldionne added inline comments.
This revision now requires changes to proceed.


================
Comment at: libcxx/include/__string/constexpr_c_functions.h:127
 
+// TODO: find a better name
+template <class _Tp, class _Up, __enable_if_t<__is_always_bitcastable<_Up, _Tp>::value, int> = 0>
----------------
I think we are fine with `__constexpr_memmove`, but the confusion here comes from the fact that we don't have a great way of conveying what the `__count` is: is it a number of elements or a number of bytes? This is also a problem we have in our other functions like `__constexpr_memcmp_equal` and others.

One suggestion would be to introduce types like this:

```
enum class _NumberOfElements : size_t {};
enum class _NumberOfBytes : size_t {};
```

And then we could take the appropriate parameter in `__constexpr_memmove`. The benefit is that callers would now explicitly pass the value so there's no ambiguity:

```
__constexpr_memmove(dest, src, _NumberOfElements(n)) // works
__constexpr_memmove(dest, src, _NumberOfBytes(n)) // doesn't work
__constexpr_memmove(dest, src, n) // doesn't work
```

We could apply the same thing to the other functions. If we do this, perhaps we should start with a refactoring of the existing functions?



================
Comment at: libcxx/include/__string/constexpr_c_functions.h:130
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp*
+__constexpr_memmove_n(_Tp* __dest, _Up* __src, size_t __count) {
+  if (__libcpp_is_constant_evaluated()) {
----------------
Can we replace `__char_traits_move` by this?


================
Comment at: libcxx/include/__string/constexpr_c_functions.h:138
+#endif
+    if (std::__is_pointer_in_range(__dest, __dest + __count, __src)) {
+      for (; __count > 0; --__count)
----------------
This is the case where `__is_ptr_in_range(dst, dstend, src)` is true. This must be implemented using a normal forward for-loop:

```
|-------------------------------------------------|
                         ^ src                    ^ srcend
        ^ dst                         ^ dstend
```

This is the case where `__is_ptr_in_range(src, srcend, dst)` is true. This must be implemented by looping backwards from srcend to src and writing from dstend to dst.

```
|-------------------------------------------------|
        ^ src                    ^ srcend
                    ^ dst                         ^ dstend
```

Right now I think you have the logic the wrong way around. This also needs a test.

The logic should be

```
std::__is_pointer_in_range(__src, __src + __count, __dest)
```


================
Comment at: libcxx/include/__type_traits/datasizeof.h:22-23
+
+template <class _Tp>
+struct __libcpp_datasizeof {
+#if __has_cpp_attribute (__no_unique_address__)
----------------



================
Comment at: libcxx/include/__type_traits/datasizeof.h:31-32
+#else
+  template <bool = __libcpp_is_final<_Tp>::value>
+  struct _FirstPaddingByte : _Tp {
+    char __first_padding_byte_;
----------------
This fails for builtin types. Needs a test!


================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp:1
 //===----------------------------------------------------------------------===//
 //
----------------
What about `copy_n`, `copy_backward` and `move_backward`?


================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp:53-59
+    // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::copy(static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst));
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
----------------
Let's enclose this in `{}` to make it clear we're testing a separate property. (everywhere)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D151953/new/

https://reviews.llvm.org/D151953



More information about the libcxx-commits mailing list