Skip to content

Commit

Permalink
MDEV-23491: __bss_start breaks compilation of various platforms
Browse files Browse the repository at this point in the history
Remove __bss_start & Co, because systen call "write" check buffer address and return EFAULT if it is wrong.
  • Loading branch information
sanja-byelkin committed Aug 18, 2020
1 parent 5796021 commit ece0b06
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 107 deletions.
122 changes: 16 additions & 106 deletions mysys/stacktrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,107 +34,16 @@
#include <execinfo.h>
#endif

#ifdef __linux__
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
static char *heap_start;
char *__bss_start;
#else
#define PTR_SANE(p) (p)
#endif /* __linux */

void my_init_stacktrace()
{
#ifdef __linux__
heap_start = (char*) &__bss_start;
#endif /* __linux__ */
}

#ifdef __linux__

static void print_buffer(char *buffer, size_t count)
{
const char s[]= " ";
for (; count && *buffer; --count)
{
my_write_stderr(isprint(*buffer) ? buffer : s, 1);
++buffer;
}
}

/**
Access the pages of this process through /proc/self/task/<tid>/mem
in order to safely print the contents of a memory address range.
@param addr The address at the start of the memory region.
@param max_len The length of the memory region.
@return Zero on success.
*/
static int safe_print_str(const char *addr, int max_len)
{
int fd;
pid_t tid;
off_t offset;
ssize_t nbytes= 0;
size_t total, count;
char buf[256];

tid= (pid_t) syscall(SYS_gettid);

sprintf(buf, "/proc/self/task/%d/mem", tid);

if ((fd= open(buf, O_RDONLY)) < 0)
return -1;

/* Ensure that off_t can hold a pointer. */
compile_time_assert(sizeof(off_t) >= sizeof(intptr));

total= max_len;
offset= (intptr) addr;

/* Read up to the maximum number of bytes. */
while (total)
{
count= MY_MIN(sizeof(buf), total);

if ((nbytes= pread(fd, buf, count, offset)) < 0)
{
/* Just in case... */
if (errno == EINTR)
continue;
else
break;
}

/* Advance offset into memory. */
total-= nbytes;
offset+= nbytes;
addr+= nbytes;

/* Output the printable characters. */
print_buffer(buf, nbytes);

/* Break if less than requested... */
if ((count - nbytes))
break;
}

if (nbytes == -1)
my_safe_printf_stderr("Can't read from address %p", addr);

close(fd);

return 0;
}

#endif

/*
Attempt to print a char * pointer as a string.
SYNOPSIS
Prints either until the end of string ('\0'), or max_len characters have
been printed.
Prints until max_len characters have been printed.
RETURN VALUE
0 Pointer was within the heap address space.
Expand All @@ -149,24 +58,25 @@ static int safe_print_str(const char *addr, int max_len)

int my_safe_print_str(const char* val, int max_len)
{
#ifdef __linux__
char *heap_end;

// Try and make use of /proc filesystem to safely print memory contents.
if (!safe_print_str(val, max_len))
return 0;

heap_end= (char*) sbrk(0);
#endif

if (!PTR_SANE(val))
const char *orig_val= val;
if (!val)
{
my_safe_printf_stderr("%s", "is an invalid pointer");
my_safe_printf_stderr("%s", "(null)");
return 1;
}

for (; max_len && PTR_SANE(val) && *val; --max_len)
my_write_stderr((val++), 1);
for (; max_len; --max_len)
{
if (my_write_stderr((val++), 1) != 1)
{
if ((errno == EFAULT) &&(val == orig_val + 1))
{
// We can not read the address from very beginning
my_safe_printf_stderr("Can't access address %p", orig_val);
}
break;
}
}
my_safe_printf_stderr("%s", "\n");

return 0;
Expand Down
2 changes: 1 addition & 1 deletion unittest/mysys/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring
aes
queues LINK_LIBRARIES mysys)
queues stacktrace LINK_LIBRARIES mysys)
MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys)

ADD_DEFINITIONS(${SSL_DEFINES})
Expand Down
67 changes: 67 additions & 0 deletions unittest/mysys/stacktrace-t.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

/* Copyright (c) 2020, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */

#include <my_global.h>
#include <my_sys.h>
#include <stdio.h>
#include <my_stacktrace.h>
#include <tap.h>

char b_bss[10];

void test_my_safe_print_str()
{
char b_stack[10];
char *b_heap= strdup("LEGAL");
memcpy(b_stack, "LEGAL", 6);
memcpy(b_bss, "LEGAL", 6);

#ifndef __SANITIZE_ADDRESS__
fprintf(stderr, "\n===== stack =====\n");
my_safe_print_str(b_stack, 65535);
fprintf(stderr, "\n===== heap =====\n");
my_safe_print_str(b_heap, 65535);
fprintf(stderr, "\n===== BSS =====\n");
my_safe_print_str(b_bss, 65535);
fprintf(stderr, "\n===== data =====\n");
my_safe_print_str("LEGAL", 65535);
fprintf(stderr, "\n===== Above is a junk, but it is expected. =====\n");
#endif /*__SANITIZE_ADDRESS__*/
fprintf(stderr, "\n===== Nornal length test =====\n");
my_safe_print_str("LEGAL", 5);
fprintf(stderr, "\n===== NULL =====\n");
my_safe_print_str(0, 5);
#ifndef __SANITIZE_ADDRESS__
fprintf(stderr, "\n===== (const char*) 1 =====\n");
my_safe_print_str((const char*)1, 5);
#endif /*__SANITIZE_ADDRESS__*/

free(b_heap);

ok(1, "test_my_safe_print_str");
}


int main(int argc __attribute__((unused)), char **argv)
{
MY_INIT(argv[0]);
plan(1);

test_my_safe_print_str();

my_end(0);
return exit_status();
}

0 comments on commit ece0b06

Please sign in to comment.