malloc()是否分配一个连续的内存块? [英] Does malloc() allocate a contiguous block of memory?

查看:165
本文介绍了malloc()是否分配一个连续的内存块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由一个非常老的程序员编写的代码片段:-)。它会像这样

  typedef struct ts_request 
{
ts_request_buffer_header_def header;
char package [1];
} ts_request_def;

ts_request_buffer_def * request_buffer =
malloc(sizeof(ts_request_def)+(2 * 1024 * 1024));

程序员基本上是在缓冲区溢出概念。我知道代码看起来狡猾。所以我的问题是:


  1. malloc总是分配连续的内存块吗?因为在此代码中,如果块不连续,代码将失败大时间


  2. 免费(request_buffer),将释放由malloc分配的所有字节即sizeof(ts_request_def)+(2 * 1024 * 1024),
    或只有结构sizeof(ts_request_def)大小的字节




这个方法有什么明显的问题,我需要和老板讨论这个问题。


  1. 是的。

  2. 所有字节。 Malloc / free不知道或关心对象的类型,只是大小。

  3. 这是严格地说未定义的行为,但是许多实现支持的常见技巧。
    $ b 最新的C标准ISO / IEC 9899:1999(非正式的C99)允许灵活的数组成员



    这将是:

      int main(void)
    {
    struct {size_t x; char a []; } * p;
    p = malloc(sizeof * p + 100);
    if(p)
    {
    / *您现在可以安全访问p> a [99]安全* /
    }
    }

    此标准化的功能允许您避免使用您在问题中描述的常见但非标准的实施扩展。严格地说,使用非灵活的数组成员和访问超出其界限是未定义的行为,但许多实现记录和鼓励它。

    此外, gcc 允许零长度数组作为扩展名。零长度数组在标准C中是非法的,但是gcc在C99之前引入了这个特性,给了我们灵活的数组成员。



    在回应注释时,我将解释为什么下面的代码段是技术上未定义的行为。章节编号我引用参考C99(ISO / IEC 9899:1999)

      struct {
    char arr [1] ;
    } * x;
    x = malloc(sizeof * x + 1024);
    x-> arr [23] = 42;

    首先,6.5.2.1#2显示a [i]与(* +(i))),所以x-> arr [23]等同于(*((x-> arr)+(23)现在,6.5.6#8(添加指针和整数)说:


    如果指针操作数和结果指向同一数组对象的元素,或者一个超过数组对象的最后一个元素,则评估不会产生溢出;否则行为未定义


    因为这个原因,因为x-> arr [23]不在数组内,所以行为是未定义的。你可能仍然认为它是好的,因为malloc()意味着数组现在已经扩展,但这不是严格的情况。信息性附录J.2(列出了未定义行为的例子)以一个例子提供了进一步的说明:


    数组下标超出范围,即使一个对象显然可以通过
    给定下标来访问(如在给定声明int
    a [4] [5])(6.5.6)的左值表达式a [1] [7] / p>


    I have a piece of code written by a very old school programmer :-) . it goes something like this

    typedef struct ts_request
    { 
      ts_request_buffer_header_def header; 
      char                         package[1]; 
    } ts_request_def; 
    
    ts_request_buffer_def* request_buffer = 
    malloc(sizeof(ts_request_def) + (2 * 1024 * 1024));
    

    the programmer basically is working on a buffer overflow concept. I know the code looks dodgy. so my questions are:

    1. Does malloc always allocate contiguous block of memory ?. because in this code if the blocks are not contiguous , the code will fail big time

    2. Doing free(request_buffer) , will it free all the bytes allocated by malloc i.e sizeof(ts_request_def) + (2 * 1024 * 1024), or only the bytes of the size of the structure sizeof(ts_request_def)

    3. Do you see any evident problems with this approach , i need to discuss this with my boss and would like to point out any loopholes with this approach

    解决方案

    To answer your numbered points.

    1. Yes.
    2. All the bytes. Malloc/free doesn't know or care about the type of the object, just the size.
    3. It is strictly speaking undefined behaviour, but a common trick supported by many implementations. See below for other alternatives.

    The latest C standard, ISO/IEC 9899:1999 (informally C99), allows flexible array members.

    An example of this would be:

    int main(void)
    {       
        struct { size_t x; char a[]; } *p;
        p = malloc(sizeof *p + 100);
        if (p)
        {
            /* You can now access up to p->a[99] safely */
        }
    }
    

    This now standardized feature allowed you to avoid using the common, but non-standard, implementation extension that you describe in your question. Strictly speaking, using a non-flexible array member and accessing beyond its bounds is undefined behaviour, but many implementations document and encourage it.

    Furthermore, gcc allows zero-length arrays as an extension. Zero-length arrays are illegal in standard C, but gcc introduced this feature before C99 gave us flexible array members.

    In a response to a comment, I will explain why the snippet below is technically undefined behaviour. Section numbers I quote refer to C99 (ISO/IEC 9899:1999)

    struct {
        char arr[1];
    } *x;
    x = malloc(sizeof *x + 1024);
    x->arr[23] = 42;
    

    Firstly, 6.5.2.1#2 shows a[i] is identical to (*((a)+(i))), so x->arr[23] is equivalent to (*((x->arr)+(23))). Now, 6.5.6#8 (on the addition of a pointer and an integer) says:

    "If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined."

    For this reason, because x->arr[23] is not within the array, the behaviour is undefined. You might still think that it's okay because the malloc() implies the array has now been extended, but this is not strictly the case. Informative Annex J.2 (which lists examples of undefined behaviour) provides further clarification with an example:

    An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6).

    这篇关于malloc()是否分配一个连续的内存块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆