使用赋值运算符检查和对齐alloca()的临时生存期

问题描述 投票:0回答:1

在编写对大型代码库的测试和分析过程中,我必须用自己的方法替换成千上万的对alloca()的调用。在我的目标平台上,如果数字为零,则alloca()失败,因此我们想断言是这种情况。我们还希望提供一个单一调用的对齐版本。但是,alloca()具有与范围相关的特定生存期,因此尽管我想写

void * CheckAndAllocate( size_t sizeInBytes )
{
  assert( sizeInBytes > 0 );
  return alloca(p); // not safe; allocation goes out of scope on return
}

void * p = CheckAndAllocate( sizeInBytes );

显然,这不是一个选择,因为alloca()不会超过CheckAndAllocate()。

为了解决这个问题,我使用一个临时的方法编写了这个替代方法:

struct CheckSize
{
  inline CheckSize( size_t size ) { assert( size > 0 ); }
  inline void * operator=(void* other) { return other );
}

#define my_alloca(size) CheckSize(size) = alloca(size)

void foo(size_t size)
{
  void * p = my_alloca(size);
  // becomes
  void * p = CheckSize(size) = alloca(size);

  // ... use p locally for work
}

此外,我还将对齐版本定义为:

struct CheckSizeAndAlign
{
  size_t _align;
  inline CheckSizeAndAlign( size_t size, size_t align ) : _align(align) { assert( size > 0 ); }
  inline void * operator=(void* other) { return AlignUp(other, _align  ); }

#define my_alloca_aligned( size, align ) CheckSizeAndAlign(size, align ) = alloca(size + align)

void foo(size_t size, size_t alignment)
{
  void * p = my_alloca_aligned( size, alignment);
  // becomes
  void * p = CheckSizeAndAlign( size, alignment) = alloca( size + alignment )

  // ... use p locally for work
}

我的问题是-鉴于alloca返回的值正在传递临时值,是否由于某种范围而违反了alloca的分配?

我认识到alloca周围存在陷阱,可以使用多种解决方案来解决此问题,但是我希望将这些更改注入代码库而无需更改其他任何内容,而只是添加一些诊断程序。

我也只是对此特定模式感到好奇。

这是MSVC2019,CLANG和利基实时系统编译器。

c++ variable-assignment assert temporary alloca
1个回答
1
投票

我建议添加一个辅助函数来执行您的assert,调用alloca,并将分配的内存传递给回调。这是我实现的第一步:

#include <alloca.h>
#include <cassert>
#include <iostream>
#include <utility>

namespace {
    template <typename FN, typename ...ARGS>
    auto alloc_helper(std::size_t size, FN fn, ARGS && ...args) {
        assert(size > 0);
        auto p = ::alloca(size);
        return fn(p, std::forward<ARGS>(args)...);
    }
}

int main() {
    auto weird_add = [](void * p, auto init, auto other) {
        auto ip = reinterpret_cast<int *>(p);
        *ip = init;
        return *ip + other;
    };

    std::cout << alloc_helper(sizeof(int), weird_add, 10, 17) << '\n';
    return 0;
}

此解决方案的优点是只键入一次大小,再加上alloca返回的指针的作用域恰好是您要使用的大小;除非回调return是它(您可以在assert上做,但会更难看)。您可以使其他辅助函数使用其他非动态分配(例如,您在注释中提到了alloca_aligned)。

© www.soinside.com 2019 - 2024. All rights reserved.