【问题标题】:Avoid stack corruption while writing to a pointer location写入指针位置时避免堆栈损坏
【发布时间】:2021-03-16 16:03:09
【问题描述】:

假设我们有一个由 C++ 库公开的 C API,其中 C 客户端通过传递 void 指针和键来查询值。

bool GetValue(const char* key, void* val) {
     if(val != NULL) {
         // find the value using the key with some logic of library
         // lets assume found value is a int
         int foundValue = 34;
         *(int*)val = foundValue;
         return true; // or false if key not found
     }
     return false;
}

C 客户端和 C++ 库开发人员就与键关联的值的大小达成一致。 假设C++库只有intlong long int,C客户端也知道。 因此,当与"some_key" 关联的值为int 时,C 客户端的行为预计如下:

int valueHolder;
if(GetValue("some_key",&valueHolder)) {
     // do something with valueHolder
}

但是 C 客户端可以通过提供指向较少空间的指针来导致堆栈内存损坏。例如,如果 C 客户端提供了一个指向 unsigned char 的指针,而 C++ 库写入的值为 int,则可能会发生堆栈内存损坏。

所以 C 客户端应该采取适当的措施来避免这种情况。我的问题是,C++ 库如何处理这种内存损坏/崩溃情况以及如何应对崩溃或内存损坏? (一个小提示:模板或函数重载对我来说不是一个选项,因为 C++ 库无法将此类功能公开给 C 客户端)。

【问题讨论】:

  • GetValueval 指向的类型一无所知。所以你无能为力。可能你应该放弃void *val 并为不同的类型提供不同的功能。例如。 GetValueInt(const char* key, int* val)GetValueLongLöongInt(const char* key, long long int* val) 等。也许这是一个 XY Problem
  • 能否更改 API 以在指针中添加“缓冲区大小”参数?
  • C 和 C++ 都不是内存安全语言。它赋予开发者更多的权力和更多的责任。
  • @Jabberwocky。 have different functions for different types 看起来像是最后的手段。我们实际上试图避免为所有类型编写函数,但最终出现了这种情况。
  • @Debashish 当然是的,没有人声称 C++ 和 C 是安全语言。

标签: c++ c


【解决方案1】:

不幸的是,它不能变得健壮,请参阅此链接: Checking if a pointer is allocated memory or not

你可以使用类似的东西来捕捉崩溃

try {} catch (...) {}

但不能保证它会崩溃,实际上它很可能会覆盖/损坏相邻的内存。

【讨论】:

  • catch(...) 不会捕获崩溃。它只捕获异常。
  • 取决于设置,无效访问会产生异常
  • @SvenNilsson,不,不能在所有情况下进行无效访问以导致异常,仍然存在您的程序当场崩溃,破坏内部状态,甚至可能未被检测到的风险。保护违规可以导致异常,但并非所有无效访问都是保护违规。
【解决方案2】:

您只需设计 API,使值的类型明确。

例如:

bool GetIntValue(const char* key, int* val) {
     if(val != NULL && IsIntValue(key)) {
         // find the value using the key with some logic of library
         // lets assume found value is a int
         int foundValue = 34;
         val = foundValue;
         return true; 
     }
     return false;
}

bool GetSizeValue(const char* key, size_t* val) {
     if(val != NULL && IsSizeValue(key)) {
         // find the value using the key with some logic of library
         // lets assume found value is a int
         size_t foundValue = 12;
         val = foundValue;
         return true; 
     }
     return false;
}

...

或其他方式:

enum Types {
   Int,
   Size,
   ....
};

struct Variant {
   enum Types type;
   union {
       int integer;
       size_t size;
       ....
   };
};

bool GetVariantValue(const char* key, struct Variant* val) {
     if(val != NULL) {
         ...
         *val = MakeIntVariant(33);
         return true; 
     }
     return false;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 2021-12-14
    • 2015-10-06
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 2017-01-18
    相关资源
    最近更新 更多