[haiku-commits] Change in haiku[master]: bootloader: reduce stack usage

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 16 Mar 2020 19:52:58 +0000

From Adrien Destugues <pulkomandy@xxxxxxxxx>:

Adrien Destugues has uploaded this change for review. ( 
https://review.haiku-os.org/c/haiku/+/2371 ;)


Change subject: bootloader: reduce stack usage
......................................................................

bootloader: reduce stack usage

On Sparc Openboot, we get allocated a stack of only 8 kilobytes, and
each called function costs at least 176 bytes for the stack frame.

This means we need to be more careful than usual about stack usage. Move
some large-ish allocations off the stack by either making them static, or
allocated dynamically.

Add a compiler flag to error on functions which use too much stack. The
threshold is at 1023 bytes, because that's what allowed me to find the
two functions that were causing a stack overflow (open_from and
_ParseActivatedPackagesFile)
---
M build/jam/ArchitectureRules
M src/system/boot/loader/file_systems/tarfs/tarfs.cpp
M src/system/boot/loader/package_support.cpp
M src/system/boot/loader/vfs.cpp
M src/system/boot/platform/generic/text_menu.cpp
M src/system/boot/platform/openfirmware/arch/sparc/mmu.cpp
M src/system/boot/platform/openfirmware/start.cpp
7 files changed, 71 insertions(+), 31 deletions(-)



  git pull ssh://git.haiku-os.org:22/haiku refs/changes/71/2371/1

diff --git a/build/jam/ArchitectureRules b/build/jam/ArchitectureRules
index 3208f2e..4ecc6c6 100644
--- a/build/jam/ArchitectureRules
+++ b/build/jam/ArchitectureRules
@@ -527,6 +527,9 @@
                                        HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += 
-Wno-error=main -m32 ;
                                        HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += 
-Wno-error=main -m32 ;
                                }
+                       case openfirmware :
+                               HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -fno-pic 
-Wno-error=main -Wstack-usage=1023 ;
+                               HAIKU_BOOT_$(bootTarget:U)_C++FLAGS += -fno-pic 
-Wno-error=main -Wstack-usage=1023 ;
                        case * :
                                # all other bootloaders are non-PIC
                                HAIKU_BOOT_$(bootTarget:U)_CCFLAGS += -fno-pic 
-Wno-error=main ;
diff --git a/src/system/boot/loader/file_systems/tarfs/tarfs.cpp 
b/src/system/boot/loader/file_systems/tarfs/tarfs.cpp
index 552d800..3969938 100644
--- a/src/system/boot/loader/file_systems/tarfs/tarfs.cpp
+++ b/src/system/boot/loader/file_systems/tarfs/tarfs.cpp
@@ -753,10 +753,10 @@
 TarFS::Volume::_Inflate(boot::Partition* partition, void* cookie, off_t offset,
        RegionDeleter& regionDeleter, size_t* inflatedBytes)
 {
-       char in[2048];
+       char* in = (char*)malloc(2048);
        z_stream zStream = {
                (Bytef*)in,             // next in
-               sizeof(in),             // avail in
+               2048,                   // avail in
                0,                              // total in
                NULL,                   // next out
                0,                              // avail out
@@ -776,7 +776,7 @@
        bool headerRead = false;

        do {
-               ssize_t bytesRead = partition->ReadAt(cookie, offset, in, 
sizeof(in));
+               ssize_t bytesRead = partition->ReadAt(cookie, offset, in, 2048);
                if (bytesRead != (ssize_t)sizeof(in)) {
                        if (bytesRead <= 0) {
                                status = Z_STREAM_ERROR;
@@ -819,6 +819,7 @@
        } while (status == Z_OK);

        inflateEnd(&zStream);
+       free(in);

        if (status != Z_STREAM_END) {
                TRACE(("tarfs: inflating failed: %d!\n", status));
diff --git a/src/system/boot/loader/package_support.cpp 
b/src/system/boot/loader/package_support.cpp
index 12ab7c7..9c92bd5 100644
--- a/src/system/boot/loader/package_support.cpp
+++ b/src/system/boot/loader/package_support.cpp
@@ -274,16 +274,16 @@
        PackageVolumeState* state)
 {
        // find the system package
-       char systemPackageName[B_FILE_NAME_LENGTH];
+       char* systemPackageName = (char*)malloc(B_FILE_NAME_LENGTH);
        status_t error = _ParseActivatedPackagesFile(packagesDirectory, state,
-               systemPackageName, sizeof(systemPackageName));
+               systemPackageName, B_FILE_NAME_LENGTH);
        if (error == B_OK) {
                // check, if package exists
+               char* packagePath = (char*)malloc(B_PATH_NAME_LENGTH);
                for (PackageVolumeState* otherState = state; otherState != NULL;
                                otherState = fStates.GetPrevious(otherState)) {
-                       char packagePath[B_PATH_NAME_LENGTH];
                        otherState->GetPackagePath(systemPackageName, 
packagePath,
-                               sizeof(packagePath));
+                               B_PATH_NAME_LENGTH);
                        struct stat st;
                        if (get_stat(packagesDirectory, packagePath, st) == B_OK
                                && S_ISREG(st.st_mode)) {
@@ -291,6 +291,7 @@
                                break;
                        }
                }
+               free(packagePath);
        } else {
                TRACE("PackageVolumeInfo::_InitState(): failed to parse "
                        "activated-packages: %s\n", strerror(error));
@@ -310,6 +311,7 @@
                }
        }

+       free(systemPackageName);
        if (state->SystemPackage() == NULL)
                return B_ENTRY_NOT_FOUND;

@@ -322,28 +324,37 @@
        PackageVolumeState* state, char* packageName, size_t packageNameSize)
 {
        // open the activated-packages file
-       char path[3 * B_FILE_NAME_LENGTH + 2];
-       snprintf(path, sizeof(path), "%s/%s/%s",
+       static const size_t kBufferSize = 3 * B_FILE_NAME_LENGTH + 2;
+       char* path = (char*)malloc(kBufferSize);
+       snprintf(path, kBufferSize, "%s/%s/%s",
                kAdministrativeDirectory, state->Name() != NULL ? state->Name() 
: "",
                kActivatedPackagesFile);
        int fd = open_from(packagesDirectory, path, O_RDONLY);
-       if (fd < 0)
+       if (fd < 0) {
+               free(path);
                return fd;
+       }
        FileDescriptorCloser fdCloser(fd);

        struct stat st;
-       if (fstat(fd, &st) != 0)
+       if (fstat(fd, &st) != 0) {
+               free(path);
                return errno;
-       if (!S_ISREG(st.st_mode))
+       }
+       if (!S_ISREG(st.st_mode)) {
+               free(path);
                return B_ENTRY_NOT_FOUND;
+       }

        // read the file until we find the system package line
        size_t remainingBytes = 0;
        for (;;) {
                ssize_t bytesRead = read(fd, path + remainingBytes,
-                       sizeof(path) - remainingBytes - 1);
-               if (bytesRead <= 0)
+                       kBufferSize - remainingBytes - 1);
+               if (bytesRead <= 0) {
+                       free(path);
                        return B_ENTRY_NOT_FOUND;
+               }

                remainingBytes += bytesRead;
                path[remainingBytes] = '\0';
@@ -352,9 +363,11 @@
                while (char* lineEnd = strchr(line, '\n')) {
                        *lineEnd = '\0';
                        if (is_system_package(line)) {
-                               return strlcpy(packageName, line, 
packageNameSize)
+                               status_t result = strlcpy(packageName, line, 
packageNameSize)
                                                < packageNameSize
                                        ?  B_OK : B_NAME_TOO_LONG;
+                               free(path);
+                               return result;
                        }
 
                        line = lineEnd + 1;
@@ -369,5 +382,6 @@
                        remainingBytes = 0;
        }

+       free(path);
        return B_ENTRY_NOT_FOUND;
 }
diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp
index 2a57686..91b12ce 100644
--- a/src/system/boot/loader/vfs.cpp
+++ b/src/system/boot/loader/vfs.cpp
@@ -250,20 +250,25 @@
                return node;

        // the node is a symbolic link, so we have to resolve the path
-       char linkPath[B_PATH_NAME_LENGTH];
-       status_t error = node->ReadLink(linkPath, sizeof(linkPath));
+       char* linkPath = (char*)malloc(B_PATH_NAME_LENGTH);
+       status_t error = node->ReadLink(linkPath, B_PATH_NAME_LENGTH);

        node->Release();
                // we don't need this one anymore

-       if (error != B_OK)
+       if (error != B_OK) {
+               free(linkPath);
                return NULL;
+       }

        // let open_from() do the real work
        int fd = open_from(this, linkPath, O_RDONLY);
-       if (fd < 0)
+       if (fd < 0) {
+               free(linkPath);
                return NULL;
+       }

+       free(linkPath);
        node = get_node_from(fd);
        if (node != NULL)
                node->Acquire();
@@ -1031,34 +1036,45 @@
                name++;
        }

-       char path[B_PATH_NAME_LENGTH];
-       if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
+       char* path = (char*)malloc(B_PATH_NAME_LENGTH);
+       if (strlcpy(path, name, B_PATH_NAME_LENGTH) >= B_PATH_NAME_LENGTH) {
+               free(path);
                return B_NAME_TOO_LONG;
+       }
 
        Node *node;
        status_t error = get_node_for_path(directory, path, &node);
        if (error != B_OK) {
-               if (error != B_ENTRY_NOT_FOUND)
+               if (error != B_ENTRY_NOT_FOUND) {
+                       free(path);
                        return error;
+               }

-               if ((mode & O_CREAT) == 0)
+               if ((mode & O_CREAT) == 0) {
+                       free(path);
                        return B_ENTRY_NOT_FOUND;
+               }

                // try to resolve the parent directory
-               strlcpy(path, name, sizeof(path));
+               strlcpy(path, name, B_PATH_NAME_LENGTH);
                if (char* lastSlash = strrchr(path, '/')) {
-                       if (lastSlash[1] == '\0')
+                       if (lastSlash[1] == '\0') {
+                               free(path);
                                return B_ENTRY_NOT_FOUND;
+                       }

                        *lastSlash = '\0';
                        name = lastSlash + 1;

                        // resolve the directory
-                       if (get_node_for_path(directory, path, &node) != B_OK)
+                       if (get_node_for_path(directory, path, &node) != B_OK) {
+                               free(path);
                                return B_ENTRY_NOT_FOUND;
+                       }

                        if (node->Type() != S_IFDIR) {
                                node->Release();
+                               free(path);
                                return B_NOT_A_DIRECTORY;
                        }

@@ -1070,16 +1086,20 @@
                error = directory->CreateFile(name, permissions, &node);
                directory->Release();

-               if (error != B_OK)
+               if (error != B_OK) {
+                       free(path);
                        return error;
+               }
        } else if ((mode & O_EXCL) != 0) {
                node->Release();
+               free(path);
                return B_FILE_EXISTS;
        }

        int fd = open_node(node, mode);

        node->Release();
+       free(path);
        return fd;
 }

diff --git a/src/system/boot/platform/generic/text_menu.cpp 
b/src/system/boot/platform/generic/text_menu.cpp
index 611268c..f4cdc6e 100644
--- a/src/system/boot/platform/generic/text_menu.cpp
+++ b/src/system/boot/platform/generic/text_menu.cpp
@@ -159,7 +159,7 @@
                if (length > width * 2)
                        width += 2 * kOffsetX - 1;

-               char buffer[width + 1];
+               char* buffer = (char*)malloc(width + 1);
                buffer[width] = '\0';
                        // make sure the buffer is always terminated

@@ -195,6 +195,8 @@
                        print_centered(console_height() - kHelpLines + row, 
buffer);
                        row++;
                }
+
+               free(buffer);
        }
 }

diff --git a/src/system/boot/platform/openfirmware/arch/sparc/mmu.cpp 
b/src/system/boot/platform/openfirmware/arch/sparc/mmu.cpp
index 000f149..d00f814 100644
--- a/src/system/boot/platform/openfirmware/arch/sparc/mmu.cpp
+++ b/src/system/boot/platform/openfirmware/arch/sparc/mmu.cpp
@@ -100,7 +100,7 @@
                return B_ERROR;
        }

-       struct of_region<uint64, uint64> regions[64];
+       static struct of_region<uint64, uint64> regions[64];
        int count = of_getprop(package, "reg", regions, sizeof(regions));
        if (count == OF_FAILED)
                count = of_getprop(sMemoryInstance, "reg", regions, 
sizeof(regions));
@@ -185,7 +185,7 @@
        // we have proper driver support for the target hardware).
        intptr_t mmu = of_instance_to_package(sMmuInstance);

-       struct translation_map {
+       static struct translation_map {
                void *PhysicalAddress() {
                        int64_t p = data;
 #if 0
diff --git a/src/system/boot/platform/openfirmware/start.cpp 
b/src/system/boot/platform/openfirmware/start.cpp
index fb267ef..5cecbc5 100644
--- a/src/system/boot/platform/openfirmware/start.cpp
+++ b/src/system/boot/platform/openfirmware/start.cpp
@@ -85,7 +85,7 @@
 extern "C" void
 start(void *openFirmwareEntry)
 {
-       char bootargs[512];
+       static char bootargs[512];

        // stage2 args - might be set via the command line one day
        stage2_args args;

--
To view, visit https://review.haiku-os.org/c/haiku/+/2371
To unsubscribe, or for help writing mail filters, visit 
https://review.haiku-os.org/settings

Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: Ia0d13a9247e1a3fff4ce654bdffd6edb16e7cbc7
Gerrit-Change-Number: 2371
Gerrit-PatchSet: 1
Gerrit-Owner: Adrien Destugues <pulkomandy@xxxxxxxxx>
Gerrit-MessageType: newchange

Other related posts:

  • » [haiku-commits] Change in haiku[master]: bootloader: reduce stack usage - Gerrit