Blog

Implementierungshinweise zum Allokator

Bernhard Heinloth/Phillip Raffeck

2023-06-28

Sonderfall map(nullptr)

In der Aufgabenstellung wird der map-Systemaufruf zusammen mit dem Allokator für den Userspace als Beispiel gezeigt. Der Allokator verwendet intern (versteckt hinter einer Templatevariable) beim ersten Aufruf map(nullptr, ...), lässt sich also vom Kernel eine Adresse geben. Und fordert bei Bedarf dann weiteren Speicher an – braucht aber unbedingt einen zusammenhängenden Speicherbereich (und verwendet deshalb in den folgenden map-Aufrufen auch explizite Adressen).

Das bedeutet unter Umständen, dass ihr, wenn ihr den Allokator so wie in der Vorgabe verwendet, aber auch noch zusätzlich in eurer Anwendung map(nullptr, ...) aufrufen wollt, der Allokator keinen weiteren Speicher mehr rausgeben wird.

Mögliche Workarounds:

  • entweder einfach map mit expliziten Zieladressen (jenseits von 0x5000000 [Userspace + App + Allokator]) in eurer Anwendung aufrufen

  • oder alloc_buddy.h im Userspace (jedoch nicht im Kernel) patchen, zum Beispiel den Code in Zeile 355

    if ((base_ptr = reinterpret_cast<uintptr_t>(RESERVE(nullptr, size))) == NULL) {
      return NULL;
    }

    zu etwas wie

    if ((base_ptr = reinterpret_cast<uintptr_t>(RESERVE(reinterpret_cast<void*>(0x1000000000), size))) == NULL) {
      return NULL;
    }

    zu ändern, um den Heap ab 0x1000000000 starten zu lassen.

  • oder beim Aufruf mit Parameter nullptr schlicht ganz zufällige (noch unbelegte) Adressen rauszugeben. Grundlegende Idee:

    void* map(void* addr, size_t size) {
      if (addr == nullptr) {
          static uintptr_t nextPtr = 88172645463325252ull;  // TODO: Eigener Wert
          do {
              nextPtr ^= nextPtr << 13;
              nextPtr ^= nextPtr >> 7;
              nextPtr ^= nextPtr << 17;
              addr = reinterpret_cast<void*>(nextPtr);
          } while (addr < USER_SPACE || mapping->in_use(addr, size));
      }
      // ...
    }

Zurück zur Übersicht