Last active
December 1, 2024 09:03
-
-
Save pavly-gerges/069e14c16ab4f1c5d643f11ebe18094d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The following code examines multiple routines of definining dynamic buffers in C. | |
// This file fires a runtime malloc() error due to a HEAP corruption error; because of buffer overflow. | |
// Two maneuvers are introduced to fix this | |
#include <stdio.h> | |
#include <stdlib.h> | |
int main() { | |
// buffers | |
const char *value1 = "Hi"; | |
const char *value2 = "Hello\n Dynamic Buffers!"; | |
// pointer to buffers | |
const char **inputs = malloc(sizeof(char *)); | |
// automatic allocation of address buffer ??? | |
// appends new addresses to the buffer automatically! | |
*inputs = value1; | |
*(inputs + 1) = value2; | |
*(inputs + 2) = value1; | |
*(inputs + 3) = value1; | |
*(inputs + 4) = value1; | |
// printf("%s\n", ((const char*) inputs[2])); | |
// printf("%s\n", ((const char*) inputs[2])); | |
free((void *) inputs); | |
return 0; | |
} |
Caution
This solution introduces a memory access violation, and forceful write memory corruption, as debugged by Valgrind (see the invalid R/W on pre-allocated blocks!):
#include <stdio.h>
#include <stdlib.h>
int main() {
// buffers
const char *value1 = "Hi";
const char *value2 = "Hello\n Dynamic Buffers!";
// pointer to buffers
const char **inputs = malloc(sizeof(char *));
// automatic allocation of address buffer ???
// appends new addresses to the buffer automatically!
*inputs = value1;
// allocate the buffers as needed
*(inputs + 1) = malloc(sizeof(char *));
*(inputs + 1) = value1;
*(inputs + 2) = malloc(sizeof(char *));
*(inputs + 2) = value2;
*(inputs + 3) = malloc(sizeof(char *));
*(inputs + 3) = value1;
*(inputs + 4) = malloc(sizeof(char *));
*(inputs + 4) = value2;
printf("%s\n", ((const char*) inputs[2]));
printf("%s\n", ((const char*) inputs[3]));
free((void *) inputs);
return 0;
}
Valgrind memory debug:
pavl-x86-machine@pavl-g:../TestValgrindMemoryAccessVio$ valgrind ./a.out --leak-check=full
==14220== Memcheck, a memory error detector
==14220== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==14220== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==14220== Command: ./a.out --leak-check=full
==14220==
==14220== Invalid write of size 8
==14220== at 0x1091D7: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a048 is 0 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x1091E6: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a048 is 0 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x1091FB: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a050 is 8 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x10920A: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a050 is 8 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x10921F: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a058 is 16 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x10922E: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a058 is 16 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
==14220== Invalid write of size 8
==14220== at 0x109243: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a060 is 16 bytes after a block of size 16 in arena "client"
==14220==
==14220== Invalid write of size 8
==14220== at 0x109252: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a060 is 16 bytes after a block of size 16 in arena "client"
==14220==
==14220== Invalid read of size 8
==14220== at 0x10925D: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a050 is 8 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
Hello
Dynamic Buffers!
==14220== Invalid read of size 8
==14220== at 0x109270: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220== Address 0x4a8a058 is 16 bytes after a block of size 8 alloc'd
==14220== at 0x4846828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==14220== by 0x1091B5: main (in /media/pavl-x86-machine/pavl-g/Projects/TestValgrindMemoryAccessVio/a.out)
==14220==
Hi
==14220==
==14220== HEAP SUMMARY:
==14220== in use at exit: 32 bytes in 4 blocks
==14220== total heap usage: 6 allocs, 2 frees, 1,064 bytes allocated
==14220==
==14220== LEAK SUMMARY:
==14220== definitely lost: 32 bytes in 4 blocks
==14220== indirectly lost: 0 bytes in 0 blocks
==14220== possibly lost: 0 bytes in 0 blocks
==14220== still reachable: 0 bytes in 0 blocks
==14220== suppressed: 0 bytes in 0 blocks
==14220== Rerun with --leak-check=full to see details of leaked memory
==14220==
==14220== For lists of detected and suppressed errors, rerun with: -s
==14220== ERROR SUMMARY: 10 errors from 10 contexts (suppressed: 0 from 0)
The following is a board summary to the 3 solutions presented here (incl. the defective solution that introduces memory access violations):
For more, follow the GNU Libc documentation for heap manipulating algorithms.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The other solution involves pre-allocating a block for 1 element and resizing as needed enabling advanced memory control over the address buffer: