[libc-commits] [PATCH] D157653: [libc][WIP] move realloc into alloc_checker

Roland McGrath via Phabricator via libc-commits libc-commits at lists.llvm.org
Fri Aug 11 11:25:50 PDT 2023


mcgrathr added a comment.

What I meant about a custom `operator new` to do `realloc` was something like this (C++20 example and without the AllocChecker arg, which would be added here too):

  #include <span>                                                                 
  #include <cstdlib>                                                              
                                                                                  
  template<typename T>                                                            
  [[nodiscard]] inline void* operator new[] (size_t size, std::span<T> old) noexcept {                                                                           
    void* ptr = ::realloc(old.data(), old.size_bytes() + size);        
    if (!ptr) { return nullptr; }                                                 
    return static_cast<char*>(ptr) + old.size_bytes();                            
  }                                                                               
                                                                                  
  struct S { int x = 23; };                                                       
                                                                                  
  S* extend(S* old, size_t count) {                                               
    return new (std::span{old,count}) S[count];                                   
  }                                                                               
                                                                                  
  int* extend(int* old, size_t count) {                                           
    return new (std::span{old,count}) int[count];                                 
  } 

Instead of the local `span` equivalent you might want to use a custom type just so the name makes it more obvious what's being done, e.g. `new (Realloc{old, count}, ac) T[n];`.

That example shows how for a type where default-initialization is not just uninitialized, it does what you want like `new` for the original allocation does, while for a type that can be uninitialized, that's still an option with no extra overhead.
And of course you can use it with constructor arguments in a situation where that makes sense.

Note that `realloc` is also sometimes used to trim an allocation to shorter than it was, and I'm not sure there's a way to do an analogous trick for that case such that destructors get run naturally.



================
Comment at: libc/src/__support/CPP/new.h:59
+  LIBC_INLINE static void *realloc(void *ptr, size_t s, AllocChecker &ac) {
+    void *mem = ::realloc(ptr, s);
+    ac = (mem != nullptr);
----------------
You might consider making this templated so `realloc<T>` takes and returns a `T*` and takes a count that it multiplies by `sizeof(T)`.  That's also a good opportunity to `static_assert(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__);`.
That makes it more similar to `new` in terms of the invariants around static types and alignment constraints, though it's still importantly different for any type that doesn't have trivial (i.e. uninitialized) default construction.


================
Comment at: libc/src/__support/char_vector.h:37
     if (cur_str != local_buffer)
-      free(cur_str);
+      delete (cur_str);
   }
----------------
Superfluous parens aren't usually used with `delete`.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157653



More information about the libc-commits mailing list