0

I am trying to implement my own heap memory allocator, by allocating memory via sbrk() system call, and managing the return buffer. void *sbrk(intptr_t increment); return value:

From man sbrk:

On success, sbrk() returns the previous program break. (If the break was increased, then this value is a pointer to the start of the newly allocated memory). On error, (void *) -1 is re‐ turned, and errno is set to ENOMEM

#include <gnu/libc-version.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
/*
        puts (gnu_get_libc_version ());
*/

#define VP_ALIGNMENT                (4096)
#define ALIGN(size,alignment)       ( ((size) + (alignment-1)) & ~((alignment-1)) )


static void *extend_heap(int nbytes)
{
        void *sp = sbrk(ALIGN(nbytes, VP_ALIGNMENT));
        if (sp == (void*)-1) {
                perror("fails to retrieve program brk");
        }

        return sp;
}


struct S{
        char m[4096];
};


int main() {
        /* get current brk */
        void *cbrk = sbrk(0);
        printf("current prog brk: %p\n",cbrk);

        /*allocate 4096 bytes and get pointer to the start of the buffer*/ 
        struct S *buf = (struct S*)extend_heap(4000);
        printf("prog brk after allocation: %p\n",sbrk(0));
        
        int c=4096;
        do {
                buf->m[4096-c] = 'a';
        } while(--c);

        c=4096;
        do {
                assert(buf->m[4096-c] == 'a');
        } while(--c);

        return 0;
}

Compile with gcc & gcc flags: cc main.c -pedantic -Wconversion -Werror the program run as expected, but i dont understand why linux allocates a huge amount of memory, 2200hex bytes when i have asked only for 4096 ?

adding one of the gcc flags -ansi or -std=c89 produce compilation errors below:

In function ‘extend_heap’: main.c:15:20: error: initialization of ‘void *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion] 15 | void *sp = sbrk(ALIGN(nbytes, VP_ALIGNMENT)); | ^~~~ main.c: In function ‘main’: main.c:31:22: error: initialization of ‘void *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion] 31 |
void *cbrk = sbrk(0); | ^~~~

sbrk returns void*. why I am getting the error above? My glibc version = 2.31, gcc version 9.3.0

Thanks.

Adam
  • 2,820
  • 1
  • 13
  • 33
  • 1
    You'll have to track down the declaration of sbrk that you're using. If you don't get an 'implicit declaration of function' warning or error then you must be declaring sbrk returning int somewhere. – Rup Jan 18 '21 at 10:56
  • @EricPostpischil - i have fixed the Q. – Adam Jan 18 '21 at 12:35
  • If I compile that with -ansi or -std=c89 then I get "warning: implicit declaration of function sbrk", which is the problem: implicitly defined functions return int. Do you not get that? I don't recognise all the macros on the man page, but it sounds like sbrk just isn't available in ansi or C89 mode. – Rup Jan 18 '21 at 12:41
  • 2
    Why do you want to compile with C 1989? Just do not, problem solved. For whatever reason, it may be that the POSIX headers declare `sbrk` differently or not at all in that old version of C. If so, and you must use C 1989, then adapt your code to work according to the original `sbrk` declaration. (If it was declared to return an `integer`, add a cast to `void *` to the return value.) But you should not use C 1989 unless you are trying to reproduce or repair some old system. – Eric Postpischil Jan 18 '21 at 12:42
  • same error with `-std=c11` and with `-std=c18` – Adam Jan 18 '21 at 12:44
  • 1
    Ah, that explains more. I suspect that when you request a specific standard, the headers respond to it by not declaring certain things to avoid injecting them into the name space. (The compiler tells the headers about certain compilation options by defining special preprocessor macros that the headers use in `#if` statements.) A solution for that may be to define a preprocessor macros that requests the headers to declare Unix stuff. I do not remember the exact name offhand. – Eric Postpischil Jan 18 '21 at 12:46
  • 1
    Putting `#define _GNU_SOURCE 1` before any `#include` makes the warning vanish. Putting `#define _POSIX_SOURCE 1` or `#define _POSIX_C_SOURCE 200809L` does not. There may be something more appropriate than `_GNU_SOURCE` for your situation; see [this information on feature test macros](https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html). – Eric Postpischil Jan 18 '21 at 12:51
  • @Rup thanks i have deleted my comment. substracting the latest sbrk(0) from cbrk gives always 2200hex. it doesnt make any sense! – Adam Jan 18 '21 at 13:05
  • Well, it makes sense perfectly. Please note that the underlying system needs some memory to manage the memory. Apparently it sets aside some information with the requested block. Its size can be less than 0x200 bytes, but memory seems to be managed in chunks of that size. – the busybee Jan 18 '21 at 13:44

0 Answers0