0

On ubuntu 18.04 I wrote the following c program and ran it with an input of 100

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    int x;
    scanf("%d", &x);
    usleep(1);
    void *tmp = malloc(x);
    usleep(1);
    free(tmp);
    return 0;
}

The output in terminal was: (with strace)

strace ./a.out
execve("./a.out", ["./a.out"], 0x7ffd69236c10 /* 50 vars */) = 0
brk(NULL)                               = 0x55a719717000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=96020, ...}) = 0
mmap(NULL, 96020, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7acb879000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2030928, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f7acb877000
mmap(NULL, 4131552, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f7acb277000
mprotect(0x7f7acb45e000, 2097152, PROT_NONE) = 0
mmap(0x7f7acb65e000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f7acb65e000
mmap(0x7f7acb664000, 15072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f7acb664000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f7acb8784c0) = 0
mprotect(0x7f7acb65e000, 16384, PROT_READ) = 0
mprotect(0x55a718d34000, 4096, PROT_READ) = 0
mprotect(0x7f7acb891000, 4096, PROT_READ) = 0
munmap(0x7f7acb879000, 96020)           = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
brk(NULL)                               = 0x55a719717000
brk(0x55a719738000)                     = 0x55a719738000
read(0, 100
"100\n", 1024)                  = 4
nanosleep({tv_sec=0, tv_nsec=1000}, NULL) = 0
nanosleep({tv_sec=0, tv_nsec=1000}, NULL) = 0
lseek(0, -1, SEEK_CUR)                  = -1 ESPIPE (Illegal seek)
exit_group(0)                           = ?
+++ exited with 0 +++

Isn't this strange? why malloc didn't use brk or mmap for the allocation of memory (between the 2 calls for nanosleep()). What's the reason for this strange behaviour?

If I change my input to 200000 I see a call to mmap in between.

  • 1
    It calls `brk()` though – Ted Lyngmo Jul 02 '21 at 13:14
  • @TedLyngmo where do you see `brk` between nanosleep? –  Jul 02 '21 at 13:15
  • I can't edit my question when you read it change sbrk with brk –  Jul 02 '21 at 13:16
  • Why do you assume that the compiled program will do things in the order you've written them? The compiler may think: "_Why not allocate first and then sleep the time that is left?_" That would be more efficient from a users point of view. The _as-if_ rule applies here I think. – Ted Lyngmo Jul 02 '21 at 13:16
  • 1
    @daniel Compiler is free to reorder instructions, as long as the observable result is the same. – Yksisarvinen Jul 02 '21 at 13:17
  • 2
    *If I change my input to 200000 I see a call to mmap in between.* You seem to be under the impression that the heap only allocates from the OS the memory requested in malloc. It does not, it allocates a block of memory at a time when needed, and then manages that heap memory and only asks for more memory from the OS when it needs it. – Eljay Jul 02 '21 at 13:18
  • You _may_ get the `strace` you want if you turn off all optimizations. It's not guaranteed though. – Ted Lyngmo Jul 02 '21 at 13:23
  • @TedLyngmo how may I do that? –  Jul 02 '21 at 14:45
  • @daniel Some compilers accept `-O0` but, still not a guarantee. Antother idea is to make the sleep time a value only availabke at runtime. – Ted Lyngmo Jul 03 '21 at 08:00

1 Answers1

1

Isn't this strange?

No.

why malloc didn't use brk or mmap for the allocation of memory (between the 2 calls for nanosleep()).

Scenario 1: You enabled optimisation, and the optimiser sees that omitting the call to malloc is not observable, and thus it was never called.

Scernario 2: malloc was called, but it presumably didn't need to call brk nor mmap at that point. Both brk and mmap had been called earlier, possibly for purposes of malloc.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Then how can I get what I'm expecting? –  Jul 02 '21 at 14:45
  • @daniel Do something with the memory so that the optimiser cannot outsmart out, then allocate more. Try a single big allocation if you want to see a `mmap` or a series of smaller allocations to see a `brk` (if your `malloc` implmentation uses it), – eerorika Jul 02 '21 at 15:34