diff options
author | Carlos O'Donell <carlos@redhat.com> | 2016-09-29 21:54:31 -0400 |
---|---|---|
committer | Carlos O'Donell <carlos@redhat.com> | 2016-09-30 01:36:56 -0400 |
commit | d61ef7352b0026d9eeaf457dbfbb2e3fd8401e92 (patch) | |
tree | 798532132a35db0935de8cff3f10e8642e3457bb /elf/tst-_dl_addr_inside_object.c | |
parent | 29cb9293326a27576965a40d50a898ee660dff81 (diff) | |
download | glibc-d61ef7352b0026d9eeaf457dbfbb2e3fd8401e92.tar.gz glibc-d61ef7352b0026d9eeaf457dbfbb2e3fd8401e92.tar.xz glibc-d61ef7352b0026d9eeaf457dbfbb2e3fd8401e92.zip |
Bug 20292 - Simplify and test _dl_addr_inside_object
The function _dl_addr_inside_object is simplified by removing the conditional 'reladdr - l->l_phdr[n].p_vaddr >= 0' which is always true. The function is refactored into it's own object file and a unit test added to verify the correct behaviour of the function.
Diffstat (limited to 'elf/tst-_dl_addr_inside_object.c')
-rw-r--r-- | elf/tst-_dl_addr_inside_object.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/elf/tst-_dl_addr_inside_object.c b/elf/tst-_dl_addr_inside_object.c new file mode 100644 index 0000000000..d1e45815c8 --- /dev/null +++ b/elf/tst-_dl_addr_inside_object.c @@ -0,0 +1,223 @@ +/* Unit test for _dl_addr_inside_object. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <link.h> +#include <elf.h> +#include <libc-symbols.h> + +extern int internal_function _dl_addr_inside_object (struct link_map *l, + const ElfW(Addr) addr); + +static int +do_test (void) +{ + int ret, err = 0; + ElfW(Addr) addr; + struct link_map map; + ElfW(Phdr) header; + map.l_phdr = &header; + map.l_phnum = 1; + map.l_addr = 0x0; + /* Segment spans 0x2000 -> 0x4000. */ + header.p_vaddr = 0x2000; + header.p_memsz = 0x2000; + header.p_type = PT_LOAD; + /* Address is above the segment e.g. > 0x4000. */ + addr = 0x5000; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: Above: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: Above: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: Above: Invalid return value.\n"); + exit (1); + } + /* Address is inside the segment e.g. 0x2000 < addr < 0x4000. */ + addr = 0x3000; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("FAIL: Inside: Address is detected as outside the segment.\n"); + err++; + break; + case 1: + printf ("PASS: Inside: Address is detected as inside the segment.\n"); + break; + default: + printf ("FAIL: Inside: Invalid return value.\n"); + exit (1); + } + /* Address is below the segment e.g. < 0x2000. */ + addr = 0x1000; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: Below: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: Below: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: Below: Invalid return value.\n"); + exit (1); + } + /* Address is in the segment and addr == p_vaddr. */ + addr = 0x2000; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("FAIL: At p_vaddr: Address is detected as outside the segment.\n"); + err++; + break; + case 1: + printf ("PASS: At p_vaddr: Address is detected as inside the segment.\n"); + break; + default: + printf ("FAIL: At p_vaddr: Invalid return value.\n"); + exit (1); + } + /* Address is in the segment and addr == p_vaddr + p_memsz - 1. */ + addr = 0x2000 + 0x2000 - 0x1; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("FAIL: At p_memsz-1: Address is detected as outside the segment.\n"); + err++; + break; + case 1: + printf ("PASS: At p_memsz-1: Address is detected as inside the segment.\n"); + break; + default: + printf ("FAIL: At p_memsz-1: Invalid return value.\n"); + exit (1); + } + /* Address is outside the segment and addr == p_vaddr + p_memsz. */ + addr = 0x2000 + 0x2000; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: At p_memsz: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: At p_memsz: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: At p_memsz: Invalid return value.\n"); + exit (1); + } + /* Address is outside the segment and p_vaddr at maximum address. */ + addr = 0x0 - 0x2; + header.p_vaddr = 0x0 - 0x1; + header.p_memsz = 0x1; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: At max: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: At max: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: At max: Invalid return value.\n"); + exit (1); + } + /* Address is outside the segment and p_vaddr at minimum address. */ + addr = 0x1; + header.p_vaddr = 0x0; + header.p_memsz = 0x1; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: At min: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: At min: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: At min: Invalid return value.\n"); + exit (1); + } + /* Address is always inside the segment with p_memsz at max. */ + addr = 0x0; + header.p_vaddr = 0x0; + header.p_memsz = 0x0 - 0x1; + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("FAIL: At maxmem: Address is detected as outside the segment.\n"); + err++; + break; + case 1: + printf ("PASS: At maxmem: Address is detected as inside the segment.\n"); + break; + default: + printf ("FAIL: At maxmem: Invalid return value.\n"); + exit (1); + } + /* Attempt to wrap addr into the segment. + Pick a load address in the middle of the address space. + Place the test address at 0x0 so it wraps to the middle again. */ + map.l_addr = 0x0 - 0x1; + map.l_addr = map.l_addr / 2; + addr = 0; + /* Setup a segment covering 1/2 the address space. */ + header.p_vaddr = 0x0; + header.p_memsz = 0x0 - 0x1 - map.l_addr; + /* No matter where you place addr everything is shifted modulo l_addr + and even with this underflow you're always 1 byte away from being + in the range. */ + ret = _dl_addr_inside_object (&map, addr); + switch (ret) + { + case 0: + printf ("PASS: Underflow: Address is detected as outside the segment.\n"); + break; + case 1: + printf ("FAIL: Underflow: Address is detected as inside the segment.\n"); + err++; + break; + default: + printf ("FAIL: Underflow: Invalid return value.\n"); + exit (1); + } + + return err; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |