From patchwork Thu Nov 6 01:44:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123610 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E64B1385DC0F for ; Thu, 6 Nov 2025 01:47:16 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by sourceware.org (Postfix) with ESMTPS id 31125385C6F3 for ; Thu, 6 Nov 2025 01:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 31125385C6F3 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 31125385C6F3 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.24 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; cv=none; b=sWf4onqz1mQIYnb5pcmsHBXc0kZoTZTJt6AXPA80/ER4pDRFzenE3J72qbzG+wFfqVtIu1gHBn2kG2iLkY2mjmUvhkDJ+hbEVj182NQV4P0Oyb1CTlnmyqazH3UX4991BepWN8QUejhsePR2qw9oj2P8Bfiiyz4DoliaiibMCr0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; c=relaxed/simple; bh=WBCpyBvxsZ+IRRjRlk0IaHG0gTmcSPUAyjRI2XhjpW4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=qyADU+btzreObgs3/p9MYmBRQUZExagRSJYIISAiecNzpKE53jBmYV25awbNm5ZSX24EYHD4qoIvuqzjrJJTlJgj6+nhyv6XEsB3qZfHKRG/GBTbzxaoSoZv3pDIhmy/O4JeoUH0hl5tExZPwJNK2rTTjfYwvcjV7jEkIunOW8s= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 31125385C6F3 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=utP4fXAe Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp01293918b1f9f0d7f8648316d0be19b34c~1R4s8IPeD2678326783epoutp01g for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20251106014452epoutp01293918b1f9f0d7f8648316d0be19b34c~1R4s8IPeD2678326783epoutp01g DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=h46oJe3DnoH4qFPAbLBZ4vd0S4GzWgNq2R0a6PFwb0g=; h=From:To:Cc:Subject:Date:References:From; b=utP4fXAeI0OGcGgOeHjFxMOpF3NqPXZwVZEWUrIEwBHQ9J+2VrRXks9eQOBUaGEJn zg3mGKJQu+CQlFuiymK+pEI8lZX8wWaR38eoD+2QGdMLGki3+3NrYvDDtPv/bVvhP7 OO8xVNNQK8IR1Vwu31FmgMlwqwfELcXdFA4nef64= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p29aba7cd2f838b17dd604c3a65fd09331~1R4sqcC0g0565105651epcas1p2z; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p1.samsung.com (unknown [182.195.38.100]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4d24kW299qz6B9m4; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epcas1p2dfea4f2cebf640e6ac0f8fc512faaae7~1R4rSsDaF0777507775epcas1p2a; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epsmtip2d034c242b01af725980ecf48c37f9421~1R4rMKRrN2407324073epsmtip2e; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 1/9] sampling-asan: A sampling-based address sanitization for on-line memory bug detection Date: Thu, 6 Nov 2025 10:44:18 +0900 Message-Id: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-CMS-MailID: 20251106014450epcas1p2dfea4f2cebf640e6ac0f8fc512faaae7 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014450epcas1p2dfea4f2cebf640e6ac0f8fc512faaae7 References: X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org This patch introduces sampling-asan, a lightweight implementation of address sanitization (ASan) designed to reduce performance overhead of ASan. ASan implementation imposes significant performance overhead, discouraging developers from using ASan to verify their codes. As a result, developers use ASan only after a memory bug is discovered. Sampling-asan addresses this limitation by leveraging a sampling-based approach to track memory allocations and deallocations. This design significantly reduces performance overhead, so making it easier for developers to apply address sanitization for application in use. Users can configure sampling conditions through environment variables, which provides flexibility in balancing bug detection accuracy and performance. Sampling-asan is highly inspired and influenced by GWP-ASan in LLVM [1] and a published paper by Google [2]. Especially, a sampling-base approach used in sampling-asan is borrowed from the key concept of GWP-ASan. You can regard, this series of patches is an effort how to apply GWP-ASan into glibc malloc implementation. Of course, there are some different features and implementation from GWP-ASan's. Please refer a simple report of sampling-asan in Glibc Bugzilla: url: https://sourceware.org/bugzilla/show_bug.cgi?id=33461 In current version, sampling-asan is served as a shared library, named libsamasan.so. So, if you want to use sampling-asan, you should compile your code with -lsamasan. [1] https://llvm.org/docs/GwpAsan.html [2] Kostya Serebryany et al., GWP-ASan: Sampling-Based Detection of Memory-Safety Bugs in Production https://arxiv.org/abs/2311.09394 Signed-off-by: Sung-hun Kim --- include/samasan.h | 18 + sampling-asan/Makefile | 47 ++ sampling-asan/Versions | 17 + sampling-asan/samasan.h | 44 ++ sampling-asan/samasan_allocate.c | 685 ++++++++++++++++++++++++ sampling-asan/samasan_allocate.h | 71 +++ sampling-asan/samasan_backtrace.c | 58 ++ sampling-asan/samasan_backtrace.h | 30 ++ sampling-asan/samasan_common.c | 25 + sampling-asan/samasan_common.h | 110 ++++ sampling-asan/samasan_error.c | 117 ++++ sampling-asan/samasan_error.h | 53 ++ sampling-asan/samasan_fault_handler.c | 132 +++++ sampling-asan/samasan_fault_handler.h | 24 + sampling-asan/samasan_init.c | 370 +++++++++++++ sampling-asan/samasan_init.h | 35 ++ sampling-asan/samasan_report.c | 264 +++++++++ sampling-asan/samasan_report.h | 35 ++ sampling-asan/samasan_sampling.c | 67 +++ sampling-asan/samasan_sampling.h | 28 + sampling-asan/samasan_variable_init.def | 38 ++ 21 files changed, 2268 insertions(+) create mode 100644 include/samasan.h create mode 100644 sampling-asan/Makefile create mode 100644 sampling-asan/Versions create mode 100644 sampling-asan/samasan.h create mode 100644 sampling-asan/samasan_allocate.c create mode 100644 sampling-asan/samasan_allocate.h create mode 100644 sampling-asan/samasan_backtrace.c create mode 100644 sampling-asan/samasan_backtrace.h create mode 100644 sampling-asan/samasan_common.c create mode 100644 sampling-asan/samasan_common.h create mode 100644 sampling-asan/samasan_error.c create mode 100644 sampling-asan/samasan_error.h create mode 100644 sampling-asan/samasan_fault_handler.c create mode 100644 sampling-asan/samasan_fault_handler.h create mode 100644 sampling-asan/samasan_init.c create mode 100644 sampling-asan/samasan_init.h create mode 100644 sampling-asan/samasan_report.c create mode 100644 sampling-asan/samasan_report.h create mode 100644 sampling-asan/samasan_sampling.c create mode 100644 sampling-asan/samasan_sampling.h create mode 100644 sampling-asan/samasan_variable_init.def diff --git a/include/samasan.h b/include/samasan.h new file mode 100644 index 0000000000..0f3b16448e --- /dev/null +++ b/include/samasan.h @@ -0,0 +1,18 @@ +/* Sampling-asan for debugging memory allocation. + Copyright (C) 2025 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 + . */ +#include diff --git a/sampling-asan/Makefile b/sampling-asan/Makefile new file mode 100644 index 0000000000..6f27bbed0d --- /dev/null +++ b/sampling-asan/Makefile @@ -0,0 +1,47 @@ +# Copyright (C) 2025 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 +# . + +# Makefile for sampling-asan routines + +subdir := sampling-asan + +include ../Makeconfig + +dist-headers := samasan.h +headers := $(dist-headers) + +extra-libs := libsamasan +extra-libs-others := $(extra-libs) + +libsamasan-routines := \ + samasan_allocate \ + samasan_backtrace \ + samasan_common \ + samasan_error \ + samasan_fault_handler \ + samasan_init \ + samasan_report \ + samasan_sampling +# routines + +libsamasan-inhibit-o = $(filter-out .os,$(object-suffixes)) + +install-lib = libsamasan.so +install-lib-ldscripts = libsamasan.so +$(inst_libdir)/libsamasan.so: + +include ../Rules diff --git a/sampling-asan/Versions b/sampling-asan/Versions new file mode 100644 index 0000000000..8f91be534c --- /dev/null +++ b/sampling-asan/Versions @@ -0,0 +1,17 @@ +libsamasan { + GLIBC_PRIVATE { + #functions + samasan_allocate; + samasan_free; + samasan_init; + samasan_deinit; + samasan_sampling_ok; + samasan_is_pointer_in_sampling_pool; + samasan_get_size; + samasan_is_enabled; + + #testing + samasan_memory_pool_pause; + samasan_memory_pool_resume; + } +} diff --git a/sampling-asan/samasan.h b/sampling-asan/samasan.h new file mode 100644 index 0000000000..8a8b58f66a --- /dev/null +++ b/sampling-asan/samasan.h @@ -0,0 +1,44 @@ +/* Prototypes for the sampling-asan interfaces. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_H +#define _SAMASAN_H + +#include /* for size_t */ +#include /* for bool type */ + +/* a call for initializing samasan */ +extern void samasan_init (void); +/* a call for sanitized malloc/realloc (see samasan_allocate.c) */ +extern void *samasan_allocate (size_t size); +/* a call for free of sanitized allocation (see samasan_allocate.c) */ +extern void samasan_free (void *ptr); +/* a call used to decide the allocation should be sampled or not */ +extern bool samasan_sampling_ok (size_t size); +/* a call returns the size of the given memory chunk */ +extern size_t samasan_get_size (void *ptr); +/* a call to determine the given pointer is located in the sampling pool */ +extern bool samasan_is_pointer_in_sampling_pool (void *ptr); +/* a call to query whether the sampling-asan module is enabled or not */ +extern bool samasan_is_enabled (void); +/* a call to pause the memory pool */ +extern void samasan_memory_pool_pause (void); +/* a call to resume the memory pool */ +extern void samasan_memory_pool_resume (void); + +#endif /* samasan.h */ diff --git a/sampling-asan/samasan_allocate.c b/sampling-asan/samasan_allocate.c new file mode 100644 index 0000000000..bf2f930f25 --- /dev/null +++ b/sampling-asan/samasan_allocate.c @@ -0,0 +1,685 @@ +/* Definitions for the sanitized memory allocation implementation. + Copyright (C) 2025 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 + . */ + +/* Sampling-asan (in short, samasan) tries to find memory bugs, such as + use-after-free, unaligned access, double free, unallocated free, and + so on with negligible performance degradation. Samasan uses a sampling + -based address sanitization to find memory bugs. That's why this mechanism + is called sampling-asan. */ + +#include +#include +#include +#include +#include + +#include "samasan_init.h" +#include "samasan_common.h" +#include "samasan_error.h" +#include "samasan_sampling.h" +#include "samasan_allocate.h" +#include "samasan_backtrace.h" + +/* Definitions of some terms used in sampling-asan: + - memory_pool: A memory_pool is a reserved memory space to serve sanitized + memory allocation. Its size can be configured by environmental variables + (please refer samasan_init.c). The size of the memory pool is decided by + the below fomula: + size = SAMASAN_MAX_ALLOC_SIZE * SAMASAN_MAX_ON_GOING_ALLOCATIONS + + (SAMASAN_PARTITION_SIZE + 1) * SAMASAN_MAX_ON_GOING_ALLOCATIONS + - memory_pool_block: A memory_pool_block is composed of a number of pages. + It serves a sanitized memory allocation to users. The size of a + memory_pool_block is decided by SAMASAN_MAX_ALLOC_SIZE. + - chunk: A served memory area to users is called a chunk. A chunk should + be located in a memory_pool_block and must be less than a memory_pool_block. + - memory_pool_partition: A memory_pool_partition is a protected zone which + is located in the first and last places of the memory pool and between two + memory_pool_blocks. Its size is decided by SAMASAN_PARTITION_SIZE. If an + user tries to access a memory_pool_partition, the program will get the + segmentation fault. + - memory_pool_entry: It means that a pair of a memory_pool_partition and + a memory_pool_block. It is only used for the address calculation. */ + +static size_t memory_pool_size; +static size_t memory_page_size; + +static size_t memory_pool_block_size; +static size_t memory_pool_partition_size; +static size_t memory_pool_entry_size; + +static void *memory_pool; +static struct memory_pool_entry_info *memory_pool_metadata; +static int memory_pool_entry_in_use; + +#define DEFAULT_GUARD_PATTERN 0xFF +const static char guard_pattern = DEFAULT_GUARD_PATTERN; + +struct samasan_mutex free_list_mutex; +struct memory_pool_entry_info *free_list_head; +struct memory_pool_entry_info *free_list_tail; + +static uintptr_t memory_pool_begin; +static uintptr_t memory_pool_end; +/* memory_pool_begin is aligned in a page-width. Because of that, if + memory_pool_block_size is a multiple of a page, calculating the address + of a memory chunk should be offsetted by a relative address of + memory_pool_begin in a memory_pool_block_size. */ +static uintptr_t memory_pool_offset; + +/* TODO: Recursive calling of samasan functions should be prevented. + It can be tested when sampling-asan is applied malloc code base. + So, the test code should be written after applying sampling-asan.*/ +SAMASAN_TLS_SPECIFIER bool is_in_samasan = false; + +#define get_memory_pool_index_by_entry_info(entry) ((uintptr_t) entry - \ + (uintptr_t) memory_pool_metadata) / sizeof (struct memory_pool_entry_info) +#define get_partition_bytes_by_entry_info(entry) \ + ((get_memory_pool_index_by_entry_info (entry) + 1) \ + * memory_pool_partition_size) +#define get_block_bytes_by_entry_info(entry) \ + (get_memory_pool_index_by_entry_info (entry) * memory_pool_block_size) +#define get_memory_pool_block_address_by_entry_info(entry) \ + (void *) (memory_pool_begin \ + + get_partition_bytes_by_entry_info (entry) \ + + get_block_bytes_by_entry_info (entry)) + +#define get_blocks(ptr) ((uintptr_t) ptr - memory_pool_begin) \ + / memory_pool_entry_size +#define get_partitions(ptr) get_blocks (ptr) +#define get_block_bytes_by_pointer(ptr) (get_blocks (ptr) \ + * memory_pool_block_size) +#define get_partition_bytes_by_pointer(ptr) (get_partitions (ptr) \ + * memory_pool_partition_size) +#define get_memory_pool_block_offset(ptr) (get_block_bytes_by_pointer (ptr) \ + + get_partition_bytes_by_pointer (ptr)) +#define get_memory_pool_index_by_pointer(ptr) \ + (get_memory_pool_block_offset (ptr) / memory_pool_entry_size) + +bool is_pointer_in_partition (void *ptr) +{ + return (uintptr_t) ptr - memory_pool_begin + - get_memory_pool_block_offset (ptr) < memory_pool_partition_size; +} + +static inline struct memory_pool_entry_info * +get_relative_memory_pool_entry_from_pointer (void *ptr, ssize_t relative) +{ + ssize_t index = (ssize_t) get_memory_pool_index_by_pointer (ptr) + relative; + + if (SAMASAN_UNLIKELY (index < 0)) + return NULL; + if (SAMASAN_UNLIKELY ((size_t) index >= memory_pool_size)) + return NULL; + return &memory_pool_metadata[index]; +} + +struct memory_pool_entry_info * +get_memory_pool_entry_from_pointer (void *ptr) +{ + if (is_pointer_in_partition (ptr)) + /* invalid access */ + return NULL; + return get_relative_memory_pool_entry_from_pointer (ptr, 0); +} + +struct memory_pool_entry_info * +get_previous_memory_pool_entry_from_pointer (void *ptr) +{ + return get_relative_memory_pool_entry_from_pointer (ptr, 0); +} + +struct memory_pool_entry_info * +get_next_memory_pool_entry_from_pointer (void *ptr) +{ + return get_relative_memory_pool_entry_from_pointer (ptr, 1); +} + +/* A bypassed memory_pool entry should be removed from the free list */ +static inline void +remove_memory_pool_entry_from_free_list +(struct memory_pool_entry_info *entry, struct memory_pool_entry_info *prev) +{ + if (entry == free_list_head && entry == free_list_tail) + free_list_head = free_list_tail = NULL; + else + { + prev->list = entry->list; + entry->list = NULL; + if (entry == free_list_tail) + free_list_tail = prev; + } +} + +/* A memory_pool_entry is detached from the free list */ +static inline struct memory_pool_entry_info * +get_memory_pool_entry_from_free_list (void) +{ + struct memory_pool_entry_info *entry; + + samasan_assert (free_list_head != NULL, "free list is emptied!\n"); + if (free_list_head == free_list_tail) + free_list_tail = NULL; + entry = free_list_head; + free_list_head = entry->list; + entry->list = NULL; + return entry; +} + +static inline void +put_memory_pool_entry_in_free_list (struct memory_pool_entry_info *entry) +{ + if (free_list_tail) + { + free_list_tail->list = entry; + free_list_tail = entry; + } + else if (free_list_tail == NULL && free_list_head == NULL) + free_list_head = free_list_tail = entry; +} + +static struct memory_pool_entry_info * +get_free_memory_pool_entry (void) +{ + struct memory_pool_entry_info *entry; + + if (SAMASAN_UNLIKELY (samasan_atomic_read (&memory_pool_entry_in_use) + >= memory_pool_size)) + return NULL; + samasan_mutex_lock (&free_list_mutex); + entry = get_memory_pool_entry_from_free_list (); + samasan_mutex_unlock (&free_list_mutex); + entry->is_free = false; + samasan_atomic_inc (&memory_pool_entry_in_use); + return entry; +} + +#define get_pointer_offset(ptr) ((uintptr_t) ptr % memory_page_size) +#define get_page_address(ptr) ((uintptr_t) ptr - get_pointer_offset (ptr)) +#define get_page_pointer(ptr) (void *) get_page_address (ptr) +#define round_up(size, bound) ((size + bound - 1) & ~(bound - 1)) + +static inline size_t +get_page_size (void *ptr, size_t size) +{ + size_t offset = (uintptr_t) ptr - get_page_address (ptr); + return round_up (offset + size, memory_page_size); +} + +static bool +protect_range_in_block (void *start, size_t size) +{ + return mprotect (get_page_pointer (start), get_page_size (start, size), + PROT_NONE) == 0; +} + +static bool +unprotect_range_in_block (void *start, size_t size) +{ + return mprotect (get_page_pointer (start), get_page_size (start, size), + PROT_READ | PROT_WRITE) == 0; +} + +bool +bypass_block (struct memory_pool_entry_info *entry) +{ + bool ret = unprotect_range_in_block ( + get_memory_pool_block_address_by_entry_info (entry), + memory_pool_block_size); + if (!ret) + return false; + entry->is_bypassed = true; + if (entry->is_free) + { + struct memory_pool_entry_info *prev; + /* remove from free list */ + samasan_mutex_lock (&free_list_mutex); + prev = free_list_head; + while (prev->list != entry && prev != free_list_tail) + prev = prev->list; + remove_memory_pool_entry_from_free_list (entry, prev); + samasan_mutex_unlock (&free_list_mutex); + /* decrease the number of useful free blocks */ + samasan_atomic_inc (&memory_pool_entry_in_use); + } + return true; +} + +/* Styles for picking a memory chunk in a memory block: + Mostly, a memory chunk is smaller than a memory block. So, samasan should + pick the address in a selected memory block to provide a memory chunk. + The picker can take the leftmost address (left-aligned) or the rightmost + address (right-aligned) while the memory chunk does not exceed the boundary + of the memory block. Of course, it can pick the center address of the memory + block (center-aligned). The picking style can be configured by using a + environmental variable (SAMASAN_CHUNK_PICK). For details, please refer + samasan_init.c. */ +static memory_chunk_pick_style_t chunk_pick_style; + +#define pick_from_left(block, size) (void *) ((uintptr_t) block) +#define pick_from_right(block, size) (void *) ((uintptr_t) block \ + + (uintptr_t) ((memory_pool_block_size)) - size) +#define pick_center(block, size) (void *) ((uintptr_t) block \ + + (uintptr_t) ((memory_pool_block_size - size) >> 1)) +#define pick_chunk(block, size) \ + (chunk_pick_style == PICK_FROM_LEFT ? pick_from_left (block, size) : \ + chunk_pick_style == PICK_FROM_RIGHT ? pick_from_right (block, size) : \ + pick_center (block, size)) +#define get_aligned(ptr) (void *) ((uintptr_t) ptr & ~(sizeof (size_t) - 1)) + +static inline void * +allocate_in_memory_pool_block (void *block, size_t size) +{ + void *chunk = get_aligned (pick_chunk (block, size)); + samasan_assert (unprotect_range_in_block (chunk, size), + "mprotect on the allocated range is failed"); + return chunk; +} + +static void * +allocate_in_memory_pool (size_t size) +{ + struct memory_pool_entry_info *entry; + void *block; + void *chunk = NULL; + + check_in_samasan (); + entry = get_free_memory_pool_entry (); + if (!entry) + goto no_entry_out; + + block = get_memory_pool_block_address_by_entry_info (entry); + chunk = allocate_in_memory_pool_block (block, size); + entry->chunk_size = size; + entry->address = (uintptr_t) chunk; + get_backtrace (&entry->allocation_trace); + +no_entry_out: + check_out_samasan(); + return chunk; +} + +/* A guard pattern is a predefined character to detect a modification in + invalid memory area. If the illegal memory modification occurrs in the + unprotected memory block, the kernel cannot raise the fault due to the + page-wise resolution of the mprotect() call. So, samasan fills the rest + of the memory block by the guard pattern. If the pattern is modified, + samasan regards it as an invalid modification and raises an error. */ + +static void +fill_guard_pattern (void *start, size_t size) +{ + memset(start, guard_pattern, size); +} + +static void +check_guard_pattern (void *chunk, size_t size) +{ + char *ptr = (char *) get_page_pointer (chunk); + size_t chunk_page_size = get_page_size (chunk, size); + + for (size_t i = 0; i < chunk_page_size;) + { + if (&ptr[i] == chunk) + { + i += size; + continue; + } + if (ptr[i] != guard_pattern) + raise_fault_with_address(INVALID_WRITE, (uintptr_t) (ptr + i)); + i++; + } +} + +#define is_address_in_chunk(address, entry) (address >= entry->address && \ + address < (entry->address + entry->chunk_size)) + +bool +is_out_of_chunk_access (uintptr_t address, + struct memory_pool_entry_info *entry) +{ + if (!is_address_in_chunk (address, entry)) + return true; + return false; +} + +#define is_address_in_memory_pool(address) ((address >= memory_pool_begin) \ + && (address < memory_pool_end)) + +bool +is_pointer_in_memory_pool (void *ptr) +{ + return is_address_in_memory_pool ((uintptr_t) ptr); +} + +static void +deallocate_memory_chunk (void *ptr) +{ + struct memory_pool_entry_info *entry = + &memory_pool_metadata[get_memory_pool_index_by_pointer (ptr)]; + uintptr_t address = (uintptr_t) ptr; + + if (entry->is_free) + { + /* Double free: A case that the program tries to free + on the freed object. */ + raise_fault_with_address (DOUBLE_FREE, (uintptr_t) ptr); + } + if (entry->address != address) + { + /* Invalid free: The pointer does not point the start address + of the chunk. */ + raise_fault_with_address (INVALID_FREE, address); + } + check_guard_pattern(ptr, entry->chunk_size); + fill_guard_pattern(ptr, entry->chunk_size); + samasan_assert (protect_range_in_block (ptr, entry->chunk_size) == true, + "mprotect on deallocated range is failed"); + entry->is_free = true; + entry->chunk_size = 0; + entry->address = 0; + + get_backtrace (&entry->deallocation_trace); + + samasan_mutex_lock (&free_list_mutex); + put_memory_pool_entry_in_free_list (entry); + samasan_mutex_unlock (&free_list_mutex); + samasan_atomic_dec (&memory_pool_entry_in_use); +} + +/* Sampling-asan API - samasan_allocate (size_t): + Allocate a memory chunk in the preallocated memory pool. If a given + allocation size is larger than memory_pool_block_size (or zero), it + does not allow to allocate a memory chunk in the memory pool. */ + +void * +samasan_allocate (size_t size) +{ + if (SAMASAN_UNLIKELY (!is_samasan_enabled ())) + return NULL; + if (SAMASAN_UNLIKELY (is_call_in_samasan ())) + return NULL; + if (SAMASAN_UNLIKELY (size > memory_pool_block_size || size == 0)) + return NULL; + if (SAMASAN_UNLIKELY (samasan_atomic_read (&memory_pool_entry_in_use) + >= memory_pool_size)) + return NULL; + return allocate_in_memory_pool (size); +} + +/* Sampling-asan API - samasan_free (void *): + Return an allocated memory chunk to the memory pool. + Before free, samasan checks the given pointer is a memory chunk + located in the memory pool. If not, samasan just returns without + free. */ + +void +samasan_free (void *ptr) +{ + uintptr_t address = (uintptr_t) ptr; + if (SAMASAN_UNLIKELY (!is_address_in_memory_pool (address))) + return; + check_in_samasan (); + deallocate_memory_chunk (ptr); + check_out_samasan(); +} + +/* Sampling-asan API - samasan_sampling_ok (size_t) + The purpose of sampling-asan is to provide address sanitization + without paying the expensive cost. To this end, this function is given + to decide whether this memory allocation is sanitized or not. */ + +bool +samasan_sampling_ok (size_t size) +{ + if (SAMASAN_LIKELY (!is_samasan_enabled ())) + return false; + if (SAMASAN_UNLIKELY (is_call_in_samasan ())) + return false; + if (SAMASAN_UNLIKELY (samasan_atomic_read (&memory_pool_entry_in_use) + >= memory_pool_size)) + return false; + if (SAMASAN_UNLIKELY (size > memory_pool_block_size || size == 0)) + return false; + if (SAMASAN_LIKELY (!decide_allocation_sampling ())) + return false; + return true; +} + +/* Sampling-asan API: samasan_get_size (void *) + This function returns the size of the given memory chunk. If the given + pointer is not an address in the memory pool or an already freed memory + chunk, it returns zero. */ + +size_t +samasan_get_size (void *ptr) +{ + struct memory_pool_entry_info *entry; + + if (SAMASAN_UNLIKELY (!is_pointer_in_memory_pool (ptr))) + return 0; + entry = get_memory_pool_entry_from_pointer (ptr); + if (SAMASAN_UNLIKELY (!entry)) + return 0; + if (entry->is_free) + return 0; + return entry->chunk_size; +} + +/* Sampling-asan API: samasan_is_pointer_in_sampling_pool (void *) + It returns true if the given pointer is an address in the memory pool + even though it is invalid. */ + +bool +samasan_is_pointer_in_sampling_pool (void *ptr) +{ + /* We do not check the pointer is valid to detect double-free cases. */ + if (SAMASAN_UNLIKELY (is_pointer_in_memory_pool (ptr))) + return true; + return false; +} + +/* A memory pool is composed of memory blocks and partitions. + Sampling-asan uses memory blocks to serve sanitized memory allocation while + partitions are used to detect invalid memory accesses. + + The below figure depicts a case that a memory block is composed of two pages. + + |----|-----------------------|----|-- + |----|----|----|----|-- + + If a partition is accessed, the kernel raises a segmentation fault because + it is protected by a mprotect call. Block pages are allowed to be accessed + but the check-on-free will detect invalid updates on unallocated area in + block pages. */ + + +static void * +memory_pool_allocate (size_t size, size_t block_size) +{ + void *pool = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + samasan_assert (pool != MAP_FAILED, "memory pool allocation is failed"); + for (void *block = pool + memory_pool_partition_size; block < pool + size; + block += (block_size + memory_pool_partition_size)) + fill_guard_pattern (block, block_size); + samasan_assert (mprotect (pool, size, PROT_NONE) == 0, "mprotect failed"); + memory_pool_begin = (uintptr_t) pool; + memory_pool_end = (uintptr_t) pool + size; + memory_pool_offset = (uintptr_t) pool % memory_pool_block_size; + return pool; +} + +static void +memory_pool_deallocate (void *pool) +{ + samasan_assert (munmap (pool, memory_pool_block_size * memory_pool_size + + memory_pool_partition_size * (memory_pool_size + 1)) == 0, + "memory pool deallocation is failed"); +} + +static void * +memory_pool_metadata_allocate (size_t size) +{ + void *metadata = mmap (NULL, size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + samasan_assert (metadata != MAP_FAILED, + "memory pool metadata allocation is failed"); + return metadata; +} + +static void +memory_pool_metadata_deallocate (void *metadata) +{ + samasan_assert (munmap (metadata, sizeof (struct memory_pool_entry_info) + * memory_pool_size) == 0, + "memory pool metadata deallocation is failed"); +} + +static void +memory_pool_metadata_init (void) +{ + memset (memory_pool_metadata, 0, sizeof (struct memory_pool_entry_info) + * memory_pool_size); + for (size_t i = 0; i < memory_pool_size; i++) + { + memory_pool_metadata[i].is_free = true; + if (SAMASAN_UNLIKELY (!free_list_head)) + free_list_head = &memory_pool_metadata[i]; + else + { + memory_pool_metadata[i].list = free_list_head; + free_list_head = &memory_pool_metadata[i]; + } + if (SAMASAN_UNLIKELY (!free_list_tail)) + free_list_tail = &memory_pool_metadata[i]; + } +} + +static size_t +get_page_aligned_alloc_size (uint32_t size) +{ + if (size % memory_page_size > 0) + return size - (size % memory_page_size) + memory_page_size; + return size; +} + +/* Functions for pthread_atfork() */ +static bool fork_handler_installed = false; + +/* Sampling-asan API: samasan_memory_pool_pause (void) + It stops the memory pool to synchronize with the child. */ + +void +samasan_memory_pool_pause (void) +{ + samasan_mutex_lock (&free_list_mutex); +} + +/* Sampling-asan API: samasan_memory_pool_resume (void) + It restarts the memory pool to synchronize with the child. */ + +void +samasan_memory_pool_resume (void) +{ + samasan_mutex_unlock (&free_list_mutex); +} + +void +samasan_install_fork_handler (void) +{ + if (! samasan_atomic_compare_and_change (&fork_handler_installed, true, false)) + { + pthread_atfork (samasan_memory_pool_pause, + samasan_memory_pool_resume, + samasan_memory_pool_resume); + } +} + +void +samasan_uninstall_fork_handler (void) +{ + // Do nothing, because there is no unregister function + // for pthread_atfork like UNREGISTER_ATFORK outside libc.so. +} + +bool +samasan_memory_pool_init (uint32_t pool_size, + uint32_t alloc_size, + uint32_t partition_size, + memory_chunk_pick_style_t style) +{ + size_t memory_pool_size_in_bytes; + + memory_page_size = get_system_page_size (); + memory_pool_size = pool_size; + if (alloc_size >= memory_page_size) + memory_pool_block_size = get_page_aligned_alloc_size (alloc_size); + else + memory_pool_block_size = memory_page_size; + memory_pool_partition_size = partition_size; + memory_pool_entry_size = memory_pool_block_size + memory_pool_partition_size; + memory_pool_size_in_bytes = memory_pool_block_size + * memory_pool_size + + (memory_pool_size + 1) + * memory_pool_partition_size; + + memory_pool = memory_pool_allocate (memory_pool_size_in_bytes, + memory_pool_block_size); + if (SAMASAN_UNLIKELY (!memory_pool)) + return false; + memory_pool_metadata = memory_pool_metadata_allocate ( + sizeof (struct memory_pool_entry_info) + * memory_pool_size); + if (SAMASAN_UNLIKELY (!memory_pool_metadata)) + { + memory_pool_deallocate (memory_pool); + return false; + } + + chunk_pick_style = style; + memory_pool_metadata_init (); + samasan_mutex_init (&free_list_mutex); + samasan_atomic_write (&memory_pool_entry_in_use, 0); + return true; +} + +static inline void +memory_pool_free_list_deinit (void) +{ + free_list_head = free_list_tail = NULL; +} + +void +samasan_memory_pool_deinit (void) +{ + if (memory_pool) + memory_pool_deallocate (memory_pool); + memory_pool = NULL; + if (memory_pool_metadata) + memory_pool_metadata_deallocate (memory_pool_metadata); + memory_pool_metadata = NULL; + + memory_pool_free_list_deinit (); + + memory_pool_block_size = 0; + memory_pool_partition_size = 0; + memory_pool_entry_size = 0; + memory_page_size = 0; + memory_pool_size = 0; + chunk_pick_style = PICK_END; +} diff --git a/sampling-asan/samasan_allocate.h b/sampling-asan/samasan_allocate.h new file mode 100644 index 0000000000..7e4fae68da --- /dev/null +++ b/sampling-asan/samasan_allocate.h @@ -0,0 +1,71 @@ +/* Prototypes and type definitions for sanitized allocation in the + sampling-asan implementation. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_ALLOCATE_H +#define _SAMASAN_ALLOCATE_H + +#include +#include /* for mmap/munmap */ + +/* For allocation/deallocation traces */ +#define INVALID_TID 0UL + +#define ALLOCATION_TRACE_SIZE 256 +struct memory_pool_trace { + void *stacktrace[ALLOCATION_TRACE_SIZE]; + size_t trace_size; + uint64_t tid; +}; + +struct memory_pool_entry_info { + struct memory_pool_trace allocation_trace; + struct memory_pool_trace deallocation_trace; + struct memory_pool_entry_info *list; /* listed in a free list */ + uintptr_t address; + uint32_t chunk_size:30; + bool is_bypassed:1; + bool is_free:1; +}; + +typedef enum memory_chunk_pick_style { + PICK_FROM_LEFT = 0, + PICK_CENTER, + PICK_FROM_RIGHT, + PICK_END, +} memory_chunk_pick_style_t; + +extern struct memory_pool_entry_info + *get_memory_pool_entry_from_pointer (void *ptr); +extern struct memory_pool_entry_info + *get_previous_memory_pool_entry_from_pointer (void *ptr); +extern struct memory_pool_entry_info + *get_next_memory_pool_entry_from_pointer (void *ptr); +extern bool bypass_block (struct memory_pool_entry_info *entry); +extern bool is_pointer_in_partition (void *ptr); +extern bool is_out_of_chunk_access (uintptr_t address, + struct memory_pool_entry_info *entry); +extern bool is_pointer_in_memory_pool (void *ptr); +extern void samasan_install_fork_handler (void); +extern void samasan_uninstall_fork_handler (void); +extern bool samasan_memory_pool_init (uint32_t pool_size, + uint32_t alloc_size, uint32_t partition_size, + memory_chunk_pick_style_t style); +extern void samasan_memory_pool_deinit (void); + +#endif /* samasan_allocate.h */ diff --git a/sampling-asan/samasan_backtrace.c b/sampling-asan/samasan_backtrace.c new file mode 100644 index 0000000000..c671c3cd92 --- /dev/null +++ b/sampling-asan/samasan_backtrace.c @@ -0,0 +1,58 @@ +/* Definitions for the backtracing feature used in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include + +#include "samasan_allocate.h" + +/* By default, we use glibc's backtrace to get backtrace. */ +void +get_backtrace (struct memory_pool_trace *trace) +{ + trace->trace_size = + backtrace ((void **) trace->stacktrace, ALLOCATION_TRACE_SIZE); + trace->tid = gettid (); +} + +void +print_backtrace (struct memory_pool_trace *trace, int stream, + ssize_t (*report_printf) (int, const char *, ...)) +{ + char **symbols; + + if (trace->trace_size == 0) + { + report_printf(stream, "samasan error - Cannot track the stack trace\n"); + return; + } + + symbols = backtrace_symbols ((void **) trace->stacktrace, trace->trace_size); + for (size_t i = 0; i < trace->trace_size; i++) + { + if (!symbols) + report_printf (stream, " #%zu %p\n", i, trace->stacktrace[i]); + else + report_printf (stream, " #%zu %s\n", i, symbols[i]); + } + if (symbols) + free (symbols); +} diff --git a/sampling-asan/samasan_backtrace.h b/sampling-asan/samasan_backtrace.h new file mode 100644 index 0000000000..ea32ab283c --- /dev/null +++ b/sampling-asan/samasan_backtrace.h @@ -0,0 +1,30 @@ +/* Prototypes for the backtrace feature used in sampling-asan. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_BACKTRACE_H +#define _SAMASAN_BACKTRACE_H + +#include + +#include "samasan_allocate.h" + +extern void get_backtrace (struct memory_pool_trace *trace); +extern void print_backtrace (struct memory_pool_trace *trace, int stream, + ssize_t (report_printf) (int, const char *, ...)); + +#endif /* samasan_backtrace.h */ diff --git a/sampling-asan/samasan_common.c b/sampling-asan/samasan_common.c new file mode 100644 index 0000000000..45ae532711 --- /dev/null +++ b/sampling-asan/samasan_common.c @@ -0,0 +1,25 @@ +/* Definitions for sampling-asan common functions. + Copyright (C) 2025 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 + . */ + +#include "samasan_common.h" + +bool +samasan_mutex_trylock (struct samasan_mutex *mutex) +{ + return pthread_mutex_trylock (&mutex->lock); +} diff --git a/sampling-asan/samasan_common.h b/sampling-asan/samasan_common.h new file mode 100644 index 0000000000..9b5c040108 --- /dev/null +++ b/sampling-asan/samasan_common.h @@ -0,0 +1,110 @@ +/* Prototypes and definitions for sampling-asan common functions. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_COMMON_H +#define _SAMASAN_COMMON_H + +#include /* for fprintf */ +#include /* for size_t */ +#include /* for bool type */ +#include /* for __sysconf */ +#include /* for mutex */ +#include /* for atomic operations */ +#include + +#define SAMASAN_TLS_SPECIFIER __thread \ + __attribute__ ((tls_model ("initial-exec"))) + +#define SAMASAN_UNLIKELY(cond) __builtin_expect (!!(cond), 0) +#define SAMASAN_LIKELY(cond) __builtin_expect (!!(cond), 1) + +#define samasan_atomic_read(var) atomic_load_relaxed (var) +#define samasan_atomic_write(var, val) atomic_store_relaxed (var, val) +#define samasan_atomic_inc(var) atomic_fetch_add_release (var, 1) +#define samasan_atomic_dec(var) atomic_fetch_add_release (var, -1) +#define samasan_atomic_compare_and_change(var, newval, oldval) \ + ({ \ + __atomic_check_size_ls((var)); \ + __typeof (*(var)) __old = (oldval); \ + !__atomic_compare_exchange_n ((var), (void *)&(__old), (newval), 0, \ + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); \ + }) + +/* defined in samasan_allocate.c */ +extern SAMASAN_TLS_SPECIFIER bool is_in_samasan; + +#define check_in_samasan() is_in_samasan = true +#define check_out_samasan() is_in_samasan = false +#define is_call_in_samasan() is_in_samasan == true + +static inline size_t +get_system_page_size (void) +{ + return __sysconf(_SC_PAGESIZE); +} + +static inline void +__samasan_exit (void) +{ + __builtin_trap (); +} + +#define samasan_exit_with_message(...) do \ +{ \ + fprintf (stderr, __VA_ARGS__); \ + __samasan_exit (); \ +} while (0); \ + +static inline void +__samasan_assert +(bool condition, const char *msg, const char *file, unsigned long line) +{ + if (condition) + return; + samasan_exit_with_message ("%s: %s: %lu: %s %m\n", file, __func__, line, msg); + /* never reached */ +} + +#define samasan_assert(condition, msg) \ + __samasan_assert(condition, msg, __FILE__, __LINE__) + +struct samasan_mutex { + pthread_mutex_t lock; +}; + +static inline void +samasan_mutex_init (struct samasan_mutex *mutex) +{ + pthread_mutex_init (&mutex->lock, NULL); +} + +static inline void +samasan_mutex_lock (struct samasan_mutex *mutex) +{ + pthread_mutex_lock (&mutex->lock); +} + +static inline void +samasan_mutex_unlock (struct samasan_mutex *mutex) +{ + pthread_mutex_unlock (&mutex->lock); +} + +extern bool samasan_mutex_trylock (struct samasan_mutex *mutex); + +#endif /* samasan_common.h */ diff --git a/sampling-asan/samasan_error.c b/sampling-asan/samasan_error.c new file mode 100644 index 0000000000..378238ab74 --- /dev/null +++ b/sampling-asan/samasan_error.c @@ -0,0 +1,117 @@ +/* Definitions for the error functions in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include /* for mmap/munmap */ + +#include "samasan_common.h" +#include "samasan_error.h" +#include "samasan_report.h" +#include "samasan_allocate.h" + +/* tracking error */ +static samasan_error_t current_error = NO_ERROR; +static uintptr_t fault_address; +static void *fault_area; + +static const char *error_to_string[] = { + "INVALID_FREE", + "DOUBLE_FREE", + "USE_AFTER_FREE", + "INVALID_ACCESS", + "INVALID_WRITE", + "OUT_OF_MEMORY_POOL", + "UNKNOWN_ERROR", +}; + +const char * +get_error_name (samasan_error_t error) +{ + return error_to_string[error]; +} + +samasan_error_t +get_current_error (void) +{ + return current_error; +} + +uintptr_t +get_fault_address (void) +{ + return fault_address; +} + +void +raise_fault_with_address (samasan_error_t error, uintptr_t address) +{ + volatile char *fault; + + current_error = error; + fault_address = address; + + fault = (char *) fault_area; + *fault = 0; /* raise segmentation fault */ + + /* unreachable */ + __builtin_trap (); +} + +samasan_error_t +diagnose_error (void *ptr, struct memory_pool_entry_info *entry) +{ + if (!is_pointer_in_memory_pool (ptr)) + return OUT_OF_MEMORY_POOL; + if (!entry) + { + if (is_pointer_in_partition (ptr)) + return INVALID_ACCESS; + return UNKNOWN_ERROR; + } + if (entry->is_free) + { + if (entry->deallocation_trace.tid == INVALID_TID) + /* The entry has never been allocated. */ + return INVALID_ACCESS; + return USE_AFTER_FREE; + } + if (is_out_of_chunk_access ((uintptr_t) ptr, entry)) + return INVALID_ACCESS; + return UNKNOWN_ERROR; +} + +bool +samasan_error_init (void) +{ + fault_area = mmap (NULL, get_system_page_size (), PROT_NONE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + samasan_assert (fault_area != MAP_FAILED, + "fault area allocation is failed\n"); + return true; +} + +void +samasan_error_deinit (void) +{ + if (fault_area) + { + samasan_assert (munmap (fault_area, get_system_page_size ()) == 0, + "failed to unmap fault area"); + fault_area = NULL; + } +} diff --git a/sampling-asan/samasan_error.h b/sampling-asan/samasan_error.h new file mode 100644 index 0000000000..3ee0bd96b9 --- /dev/null +++ b/sampling-asan/samasan_error.h @@ -0,0 +1,53 @@ +/* Prototypes for the error functions in sampling-asan. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_ERROR_H +#define _SAMASAN_ERROR_H + +#include /* for uintptr_t type */ +#include /* for bool type */ + +#include "samasan_allocate.h" + +typedef enum samasan_error { + NO_ERROR = -1, /* no error occurred */ + INVALID_FREE = 0, /* try to free an address at out of the allocated chunk */ + DOUBLE_FREE, /* try to free already freed one */ + USE_AFTER_FREE, /* try to access the freed memory chunk */ + INVALID_ACCESS, /* try to access the area out of the allocated chunk */ + INVALID_WRITE, /* write on invalid range, detected by check-on-free */ + OUT_OF_MEMORY_POOL, /* a given address is out of the memory pool */ + UNKNOWN_ERROR, /* an unindentified error */ +} samasan_error_t; + +extern const char *get_error_name (samasan_error_t error); +extern samasan_error_t get_current_error (void); +extern uintptr_t get_fault_address (void); +extern samasan_error_t diagnose_error (void *ptr, + struct memory_pool_entry_info *entry); +extern void raise_fault_with_address (samasan_error_t error, + uintptr_t address); +extern bool samasan_error_init (void); +extern void samasan_error_deinit (void); + +#define is_bypassable_error(error) ( \ + error == USE_AFTER_FREE || \ + error == INVALID_ACCESS || \ + error == INVALID_WRITE) + +#endif /* samasan_error.h */ diff --git a/sampling-asan/samasan_fault_handler.c b/sampling-asan/samasan_fault_handler.c new file mode 100644 index 0000000000..3767c7015e --- /dev/null +++ b/sampling-asan/samasan_fault_handler.c @@ -0,0 +1,132 @@ +/* Definitions for the sampling-asan fault handler. + Copyright (C) 2025 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 + . */ + +#include + +#include "samasan_allocate.h" +#include "samasan_error.h" +#include "samasan_common.h" +#include "samasan_report.h" +#include "samasan_init.h" +#include "samasan_backtrace.h" + +static struct sigaction default_handler; +static bool handler_installed; + +static void +segfault_handler (int sig, siginfo_t *info, void *context) +{ + struct memory_pool_entry_info *entry; + struct memory_pool_entry_info *entry_at_next = NULL; + samasan_error_t error; + uintptr_t fault_address; + struct memory_pool_trace fault_stack_trace; + void *fault_ptr; + + check_in_samasan (); + + fault_address = get_fault_address (); + fault_ptr = (void *) fault_address; + if (fault_address == 0) + { + fault_ptr = info->si_addr; + fault_address = (uintptr_t) fault_ptr; + } + + entry = get_memory_pool_entry_from_pointer (fault_ptr); + error = get_current_error (); + if (error == NO_ERROR) + error = diagnose_error (fault_ptr, entry); + if (error == INVALID_ACCESS) + { + entry = get_previous_memory_pool_entry_from_pointer (fault_ptr); + entry_at_next = get_next_memory_pool_entry_from_pointer (fault_ptr); + } + + /* get a stack trace of the faulted instruction */ + get_backtrace (&fault_stack_trace); + samasan_report_write (error, fault_address, entry, entry_at_next, + &fault_stack_trace); + + /* Crash forwarding */ + if (default_handler.sa_handler == SIG_DFL) + { + /* If the error is not reported by sampling-asan, forward the crash + to the default handler. */ + if (samasan_continue_on_crash == false || + !entry || + !is_bypassable_error (error) || + !bypass_block (entry)) + { + __sigaction (SIGSEGV, &default_handler, NULL); + raise (SIGSEGV); + } + } + else if (default_handler.sa_handler == SIG_IGN) + { + /* This error is not reported by sampling-asan */ + __sigaction (SIGSEGV, &default_handler, NULL); + raise (SIGSEGV); + } + else + { + if (default_handler.sa_flags & SA_SIGINFO) + default_handler.sa_sigaction (sig, info, context); + else + default_handler.sa_handler (sig); + } + + check_out_samasan (); +} + +static void +install_signal_handler (void) +{ + struct sigaction action; + + if (SAMASAN_UNLIKELY (handler_installed)) + return; + + sigemptyset (&action.sa_mask); + action.sa_sigaction = segfault_handler; + action.sa_flags = SA_SIGINFO; + __sigaction (SIGSEGV, &action, &default_handler); + handler_installed = true; +} + +static void +uninstall_signal_handler (void) +{ + if (SAMASAN_UNLIKELY (!handler_installed)) + return; + __sigaction (SIGSEGV, &default_handler, NULL); + handler_installed = false; +} + +bool +samasan_fault_handler_init (void) +{ + install_signal_handler (); + return true; +} + +void +samasan_fault_handler_deinit (void) +{ + uninstall_signal_handler (); +} diff --git a/sampling-asan/samasan_fault_handler.h b/sampling-asan/samasan_fault_handler.h new file mode 100644 index 0000000000..48deb50d93 --- /dev/null +++ b/sampling-asan/samasan_fault_handler.h @@ -0,0 +1,24 @@ +/* Prototypes and definition for a sampling-asan fault handler. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_FAULT_HANDLER_H +#define _SAMASAN_FAULT_HANDLER_H + +extern bool samasan_fault_handler_init (void); + +#endif /* samasan_fault_handler.h */ diff --git a/sampling-asan/samasan_init.c b/sampling-asan/samasan_init.c new file mode 100644 index 0000000000..086618569e --- /dev/null +++ b/sampling-asan/samasan_init.c @@ -0,0 +1,370 @@ +/* Definitions for sampling-asan initialization. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include + +#include "samasan_common.h" +#include "samasan_allocate.h" +#include "samasan_sampling.h" +#include "samasan_report.h" +#include "samasan_error.h" +#include "samasan_fault_handler.h" + +typedef enum samasan_option { + SAMASAN_ENABLE, + SAMASAN_MAX_ALLOC_SIZE, + SAMASAN_MAX_ON_GOING_ALLOCATIONS, + SAMASAN_SAMPLING_RATE, + SAMASAN_OUTPUT_PATH, + SAMASAN_PARTITION_SIZE, + SAMASAN_PAUSE_ON_FORK, + SAMASAN_CHUNK_PICK, + SAMASAN_CONTINUE_ON_CRASH, + SAMASAN_OPTIONS, +} samasan_option_t; + +static const char *options_string[SAMASAN_OPTIONS + 1] = { + "SAMASAN_ENABLE", + "SAMASAN_MAX_ALLOC_SIZE", + "SAMASAN_MAX_ON_GOING_ALLOCATIONS", + "SAMASAN_SAMPLING_RATE", + "SAMASAN_OUTPUT_PATH", + "SAMASAN_PARTITION_SIZE", + "SAMASAN_PAUSE_ON_FORK", + "SAMASAN_CHUNK_PICK", + "SAMASAN_CONTINUE_ON_CRASH", + "SAMASAN_OPTIONS", +}; + +union samasan_variable { + uint32_t i_value; + bool b_value; + const char *c_value; +}; + +struct samasan_configurable { + union samasan_variable value; + /* if the value should be located in [min, max), the configurable + can define a range. */ + struct { + uint32_t max; /* a value should be smaller than max */ + uint32_t min; /* a value should be larger (or equal) than (to) min*/ + } range; +}; + +static struct samasan_configurable *samasan_configurables; +bool samasan_enabled; /* sampling-asan is on-going or not */ +bool samasan_continue_on_crash; /* the program keeps running even after + a crash reported by sampling-asan */ + +bool +samasan_is_enabled (void) +{ + return samasan_enabled; +} + +static inline void +samasan_set_variable_uint (samasan_option_t option, uint32_t value) +{ + samasan_configurables[option].value.i_value = value; +} + +static inline void +samasan_set_variable_bool (samasan_option_t option, bool value) +{ + samasan_configurables[option].value.b_value = value; +} + +static inline void +samasan_set_variable_char (samasan_option_t option, const char *value) +{ + samasan_configurables[option].value.c_value = value; +} + +static inline void +samasan_set_variable_range (samasan_option_t option, uint32_t max, + uint32_t min) +{ + samasan_configurables[option].range.max = max; + samasan_configurables[option].range.min = min; +} + +#define samasan_set_variable(index, value) \ + _Generic ((value), \ + uint32_t: samasan_set_variable_uint, \ + const char *: samasan_set_variable_char, \ + char *: samasan_set_variable_char, \ + bool: samasan_set_variable_bool) (index, value) + +#define samasan_get_variable(index) samasan_configurables[index].value + +#define samasan_check_variable_range(index, value) \ + (value >= samasan_configurables[index].range.min && \ + value <= samasan_configurables[index].range.max) + +#define samasan_get_enabled() samasan_get_variable (SAMASAN_ENABLE).b_value +#define samasan_get_output_path() \ + samasan_get_variable (SAMASAN_OUTPUT_PATH).c_value +#define samasan_get_sampling_rate() \ + samasan_get_variable (SAMASAN_SAMPLING_RATE).i_value +#define samasan_get_max_on_going_allocations() \ + samasan_get_variable (SAMASAN_MAX_ON_GOING_ALLOCATIONS).i_value +#define samasan_get_max_alloc_size() \ + samasan_get_variable (SAMASAN_MAX_ALLOC_SIZE).i_value +#define samasan_get_partition_size() \ + samasan_get_variable (SAMASAN_PARTITION_SIZE).i_value +#define samasan_get_pause_on_fork() \ + samasan_get_variable (SAMASAN_PAUSE_ON_FORK).b_value +#define samasan_get_chunk_pick_style() \ + samasan_get_variable (SAMASAN_CHUNK_PICK).i_value +#define samasan_get_continue_on_crash() \ + samasan_get_variable (SAMASAN_CONTINUE_ON_CRASH).b_value + +static bool +import_samasan_variable (int type, const char *val) +{ + switch (type) + { + case SAMASAN_ENABLE: + { + bool var = false; + if (!strcmp (val, "on") || !strcmp (val, "enable") + || !strcmp (val, "yes") || !strcmp (val, "true")) + var = true; + samasan_set_variable (SAMASAN_ENABLE, var); + break; + } + case SAMASAN_MAX_ALLOC_SIZE: + { + uint32_t converted = (uint32_t) atoi (val); + if (!converted) + return false; + if (!samasan_check_variable_range (SAMASAN_MAX_ALLOC_SIZE, converted)) + return false; + samasan_set_variable (SAMASAN_MAX_ALLOC_SIZE, converted); + break; + } + case SAMASAN_MAX_ON_GOING_ALLOCATIONS: + { + uint32_t converted = (uint32_t) atoi (val); + if (!converted) + return false; + if (!samasan_check_variable_range (SAMASAN_MAX_ON_GOING_ALLOCATIONS, + converted)) + return false; + samasan_set_variable (SAMASAN_MAX_ON_GOING_ALLOCATIONS, converted); + break; + } + case SAMASAN_SAMPLING_RATE: + { + uint32_t converted = (uint32_t) (atof (val) * 100000.0); + if (!samasan_check_variable_range (SAMASAN_SAMPLING_RATE, converted)) + return false; + samasan_set_variable (SAMASAN_SAMPLING_RATE, converted); + break; + } + case SAMASAN_OUTPUT_PATH: + { + if (!val) + return false; + samasan_set_variable (SAMASAN_OUTPUT_PATH, val); + break; + } + case SAMASAN_PARTITION_SIZE: + { + uint32_t converted = (uint32_t) atoi (val); + if (!samasan_check_variable_range (SAMASAN_PARTITION_SIZE, + converted)) + return false; + samasan_set_variable (SAMASAN_PARTITION_SIZE, converted); + break; + } + case SAMASAN_PAUSE_ON_FORK: + { + bool var = false; + if (!strcmp (val, "on") || !strcmp (val, "enable") + || !strcmp (val, "yes") || !strcmp (val, "true")) + var = true; + samasan_set_variable (SAMASAN_PAUSE_ON_FORK, var); + break; + } + case SAMASAN_CHUNK_PICK: + { + uint32_t pick; + if (!strcmp (val, "left") || !strcmp (val, "LEFT")) + pick = (uint32_t) PICK_FROM_LEFT; + else if (!strcmp (val, "right") || !strcmp (val, "RIGHT")) + pick = (uint32_t) PICK_FROM_RIGHT; + else if (!strcmp (val, "center") || !strcmp (val, "CENTER")) + pick = (uint32_t) PICK_CENTER; + else + return false; + samasan_set_variable (SAMASAN_CHUNK_PICK, pick); + break; + } + case SAMASAN_CONTINUE_ON_CRASH: + { + bool var = false; + if (!strcmp (val, "on") || !strcmp (val, "enable") + || !strcmp (val, "yes") || !strcmp (val, "true")) + var = true; + samasan_set_variable (SAMASAN_CONTINUE_ON_CRASH, var); + break; + } + default: + break; + } + return true; +} + +static inline bool import_samasan_variable_range +(samasan_option_t option, const char *max, const char *min) +{ + uint32_t minval, maxval; + + minval = (uint32_t) atoi (min); + maxval = (uint32_t) atoi (max); + if (maxval < minval) + return false; + + samasan_set_variable_range (option, maxval, minval); + return true; +} + +#include "samasan_variable_init.def" + +static void +samasan_variable_init (void) +{ + if (SAMASAN_UNLIKELY (!samasan_configurables)) + return; + + /* variable range initialization */ + import_samasan_variable_range (SAMASAN_SAMPLING_RATE, + MAX_SAMASAN_SAMPLING_RATE, + MIN_SAMASAN_SAMPLING_RATE); + import_samasan_variable_range (SAMASAN_MAX_ALLOC_SIZE, + MAX_SAMASAN_MAX_ALLOC_SIZE, + MIN_SAMASAN_MAX_ALLOC_SIZE); + import_samasan_variable_range (SAMASAN_MAX_ON_GOING_ALLOCATIONS, + MAX_SAMASAN_MAX_ON_GOING_ALLOCATIONS, + MIN_SAMASAN_MAX_ON_GOING_ALLOCATIONS); + import_samasan_variable_range (SAMASAN_PARTITION_SIZE, + MAX_SAMASAN_PARTITION_SIZE, + MIN_SAMASAN_PARTITION_SIZE); + + /* configurable variables initialization */ + import_samasan_variable (SAMASAN_ENABLE, + DEFAULT_SAMASAN_ENABLED); + import_samasan_variable (SAMASAN_SAMPLING_RATE, + DEFAULT_SAMASAN_SAMPLING_RATE); + import_samasan_variable (SAMASAN_MAX_ALLOC_SIZE, + DEFAULT_SAMASAN_MAX_ALLOC_SIZE); + import_samasan_variable (SAMASAN_MAX_ON_GOING_ALLOCATIONS, + DEFAULT_SAMASAN_MAX_ON_GOING_ALLOCATIONS); + import_samasan_variable (SAMASAN_OUTPUT_PATH, + DEFAULT_SAMASAN_OUTPUT_PATH); + import_samasan_variable (SAMASAN_PARTITION_SIZE, + DEFAULT_SAMASAN_PARTITION_SIZE); + import_samasan_variable (SAMASAN_PAUSE_ON_FORK, + DEFAULT_SAMASAN_PAUSE_ON_FORK); + import_samasan_variable (SAMASAN_CHUNK_PICK, + DEFAULT_SAMASAN_CHUNK_PICK); + import_samasan_variable (SAMASAN_CONTINUE_ON_CRASH, + DEFAULT_SAMASAN_CONTINUE_ON_CRASH); +} + +void +samasan_disable (void) +{ + if (samasan_enabled) + samasan_enabled = false; +} + +void +samasan_init (void) +{ + struct samasan_configurable configurables[SAMASAN_OPTIONS]; + + if (SAMASAN_UNLIKELY (samasan_enabled)) + return; + + memset (configurables, 0, sizeof (configurables)); + samasan_configurables = configurables; + + samasan_variable_init (); + + for (int i = 0; i < SAMASAN_OPTIONS; i++) + { + const char *val = getenv (options_string[i]); + if (val) + { + if (!import_samasan_variable (i, val)) + /* some variable includes a value out-of-range */ + goto err_out1; + } + } + if (!samasan_memory_pool_init (samasan_get_max_on_going_allocations (), + samasan_get_max_alloc_size (), + samasan_get_partition_size (), + samasan_get_chunk_pick_style ())) + goto err_out1; + if (!samasan_report_init (samasan_get_output_path ())) + goto err_out2; + if (!samasan_sampling_init (samasan_get_sampling_rate ())) + goto err_out3; + if (!samasan_error_init ()) + goto err_out3; + if (!samasan_fault_handler_init ()) + goto err_out4; + if (samasan_get_pause_on_fork ()) + samasan_install_fork_handler (); + if (samasan_get_continue_on_crash ()) + samasan_continue_on_crash = true; + if (samasan_get_enabled ()) + samasan_enabled = true; + samasan_configurables = NULL; + return; + +err_out4: + samasan_error_deinit (); +err_out3: + samasan_report_deinit (); +err_out2: + samasan_memory_pool_deinit (); +err_out1: + samasan_configurables = NULL; +} + +void +samasan_deinit (void) +{ + if (SAMASAN_LIKELY(samasan_enabled)) + { + samasan_error_deinit (); + samasan_memory_pool_deinit (); + samasan_report_deinit (); + samasan_uninstall_fork_handler(); + } + samasan_enabled = false; +} diff --git a/sampling-asan/samasan_init.h b/sampling-asan/samasan_init.h new file mode 100644 index 0000000000..2bb23dc48e --- /dev/null +++ b/sampling-asan/samasan_init.h @@ -0,0 +1,35 @@ +/* Prototypes and definition for sampling-asan initialization. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_INIT_H +#define _SAMASAN_INIT_H + +#include + +extern bool samasan_enabled; +extern bool samasan_continue_on_crash; + +static __inline __attribute__ ((always_inline)) bool +is_samasan_enabled (void) +{ + return samasan_enabled; +} + +extern void samasan_deinit (void); + +#endif /* samasan_init.h */ diff --git a/sampling-asan/samasan_report.c b/sampling-asan/samasan_report.c new file mode 100644 index 0000000000..b26f3fce0c --- /dev/null +++ b/sampling-asan/samasan_report.c @@ -0,0 +1,264 @@ +/* Definitions for sampling-asan reporting. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +#include "samasan_common.h" +#include "samasan_error.h" +#include "samasan_allocate.h" +#include "samasan_backtrace.h" + +static const char *report_path; +static const char *report_head = ""; +static const char *report_foot = ""; + +#define NAMELEN 255 + +static void +get_command_line (char *str) +{ + const char *path = "/proc/self/cmdline"; + int comm_fd = __open (path, O_RDONLY); + size_t pos = 0; + + if (comm_fd < 0) + goto comm_error; + + while (1) + { + size_t ret = __read (comm_fd, &str[pos], NAMELEN - pos); + if (ret == 0) + break; + if (ret < 0) + { + __close (comm_fd); + memset (str, 0, pos); + goto comm_error; + } + pos += ret; + if (pos == NAMELEN) + { + pos--; + break; + } + } + __close (comm_fd); + str[pos] = '\0'; + + return; + +comm_error: + strcpy (str, "unknown"); + return; +} + +static char * +strip_command_line (char *str) +{ + char *pos; + + if (!str) + return NULL; + pos = strrchr (str, '/'); + if (pos) + return pos + 1; + return str; +} + +static struct samasan_mutex report_lock; + +static ssize_t __report_printf (int fd, const char *format, ...) +{ +#define BUF_LEN 255 + char buffer[BUF_LEN]; + memset (buffer, 0, BUF_LEN); + va_list ap; + + samasan_mutex_lock (&report_lock); + va_start (ap, format); + vsnprintf (buffer, BUF_LEN, format, ap); + va_end (ap); + samasan_mutex_unlock (&report_lock); + + return write (fd, buffer, sizeof (buffer)); +#undef BUF_LEN +} + +static ssize_t (*report_printf) (int, const char *, ...) = + __report_printf; + +void +samasan_report_write (samasan_error_t error, uintptr_t address, + struct memory_pool_entry_info *entry, + struct memory_pool_entry_info *entry_at_next, + struct memory_pool_trace *fault_stack_trace) +{ + int stream = STDERR_FILENO; + char program_invocation_name[NAMELEN], *process_name; + const char *error_name = get_error_name (error); + + if (strcmp (report_path, "stderr")) + stream = __open (report_path, O_CREAT | O_WRONLY, 0644); + + if (SAMASAN_UNLIKELY (!stream)) + return; + memset (program_invocation_name, 0, sizeof (program_invocation_name)); + get_command_line (program_invocation_name); + process_name = strip_command_line (program_invocation_name); + report_printf (stream, "%s\n", report_head); + report_printf (stream, "A crash is occurred in %s\n", process_name); + report_printf (stream, + "A %s fault raised on 0x%" PRIxPTR "\n", error_name, address); + report_printf (stream, "\n"); + print_backtrace (fault_stack_trace, stream, report_printf); + + if (entry == NULL) + { + report_printf (stream, + "=============================================\n"); + report_printf (stream, "Cannot find allocation metadata!\n"); + report_printf (stream, "If an OUT_OF_MEMORY_POOL fault is raised, "); + report_printf (stream, + "it can be a problem caused by other memory bugs.\n"); + report_printf (stream, "You can recheck the problem with "); + report_printf (stream, "the increased sampling rate by setting "); + report_printf (stream, "\"SAMASAN_SAMPLING_RATE=\".\n"); + report_printf (stream, + "============================================\n"); + goto report_end; + } + + if (error != INVALID_ACCESS && !entry->is_free) + { + report_printf (stream, + "=============================================\n"); + report_printf (stream, + "An allocated chunk is located at 0x%" PRIxPTR " ", + entry->address); + report_printf (stream, "and occupies %" PRIu32 " bytes.\n", + entry->chunk_size); + + if (error == INVALID_FREE) + { + const bool address_after = address > entry->address; + size_t diff = address_after ? address - entry->address + : entry->address - address; + const char *direction = address_after ? "after" : "before"; + + report_printf (stream, "You tried to free on 0x%" PRIxPTR " ", address); + report_printf (stream, "and it was %zu bytes %s the allocated chunk.\n", + diff, direction); + } + report_printf (stream, + "=============================================\n"); + } + + if (error == INVALID_ACCESS) + { + if (!entry->is_free) + { + report_printf (stream, + "=============================================\n"); + report_printf (stream, + "The previous allocated chunk is located at 0x%" PRIxPTR " ", + entry->address); + report_printf (stream, "and occupies %" PRIu32 " bytes.\n", + entry->chunk_size); + report_printf (stream, + "=============================================\n"); + } + report_printf (stream, + "allocation_trace.tid); + print_backtrace (&entry->allocation_trace, stream, report_printf); + if (entry->is_free) + { + report_printf (stream, + "\n", + entry->deallocation_trace.tid); + print_backtrace (&entry->deallocation_trace, stream, report_printf); + } + if (entry_at_next == NULL) + goto report_end; + + if (!entry_at_next->is_free) + { + report_printf (stream, "=============================================\n"); + report_printf (stream, + "The next allocated chunk is located at 0x%" PRIxPTR " ", + entry_at_next->address); + report_printf (stream, "and occupies %" PRIu32 " bytes.\n", + entry_at_next->chunk_size); + report_printf (stream, "=============================================\n"); + } + report_printf (stream, + "allocation_trace.tid); + print_backtrace (&entry_at_next->allocation_trace, stream, + report_printf); + if (entry_at_next->is_free) + { + report_printf (stream, + "\n", + entry_at_next->deallocation_trace.tid); + print_backtrace (&entry_at_next->deallocation_trace, + stream, report_printf); + } + } + else + { + report_printf (stream, "\n", + entry->allocation_trace.tid); + print_backtrace (&entry->allocation_trace, stream, report_printf); + if (entry->is_free) + { + report_printf (stream, "\n", + entry->deallocation_trace.tid); + print_backtrace (&entry->deallocation_trace, stream, report_printf); + } + } + +report_end: + report_printf (stream, "%s\n", report_foot); + + if (stream != STDERR_FILENO) + __close (stream); +} + +bool +samasan_report_init (const char *output_path) +{ + samasan_mutex_init (&report_lock); + if (!strcmp (output_path, "stderr")) + report_path = "stderr"; + else + report_path = output_path; + return true; +} + +void +samasan_report_deinit (void) +{ + report_path = NULL; +} diff --git a/sampling-asan/samasan_report.h b/sampling-asan/samasan_report.h new file mode 100644 index 0000000000..df82ce42b3 --- /dev/null +++ b/sampling-asan/samasan_report.h @@ -0,0 +1,35 @@ +/* Prototypes for sampling-asan reporting. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_REPORT_H +#define _SAMASAN_REPORT_H + +#include +#include + +#include "samasan_error.h" +#include "samasan_allocate.h" + +extern void samasan_report_write (samasan_error_t error, uintptr_t address, + struct memory_pool_entry_info *entry, + struct memory_pool_entry_info *entry_at_next, + struct memory_pool_trace *fault_stack_trace); +extern bool samasan_report_init (const char *output_path); +extern void samasan_report_deinit (void); + +#endif /* samasan_report.h */ diff --git a/sampling-asan/samasan_sampling.c b/sampling-asan/samasan_sampling.c new file mode 100644 index 0000000000..54be99dd2f --- /dev/null +++ b/sampling-asan/samasan_sampling.c @@ -0,0 +1,67 @@ +/* Definitions for the sampling methods in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan_common.h" + +#define DEFAULT_SAMPLING_INITIAL_VALUE 0x19861216 +#define DEFAULT_SAMPLING_MASK 100 * 1000 +static uint32_t sampling_rate; +static uint32_t sampling_mask = DEFAULT_SAMPLING_MASK; + +static uint32_t * +get_sampling_variable (void) +{ + static SAMASAN_TLS_SPECIFIER uint32_t sampling_variable = + DEFAULT_SAMPLING_INITIAL_VALUE; + return &sampling_variable; +} + +static inline uint32_t +get_random_value (uint32_t value) +{ + value ^= value << 7; + value ^= value << 3; + value ^= value << 17; + value ^= value << 8; + return value; +} + +bool +decide_allocation_sampling (void) +{ + bool ret = false; + uint32_t value = get_random_value (*get_sampling_variable ()); + uint32_t sample = value % sampling_mask; + + if (SAMASAN_UNLIKELY (sample <= sampling_rate)) + ret = true; + *get_sampling_variable () = value; + return ret; +} + +bool +samasan_sampling_init (uint32_t given_sampling_rate) +{ + if (given_sampling_rate > DEFAULT_SAMPLING_MASK) + return false; + sampling_rate = given_sampling_rate; + return true; +} diff --git a/sampling-asan/samasan_sampling.h b/sampling-asan/samasan_sampling.h new file mode 100644 index 0000000000..1bd867fc78 --- /dev/null +++ b/sampling-asan/samasan_sampling.h @@ -0,0 +1,28 @@ +/* Prototypes for the sampling-asan sampling methods. + Copyright (C) 2025 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 + . */ + +#ifndef _SAMASAN_SAMPLING_H +#define _SAMASAN_SAMPLING_H + +#include +#include /* for bool type */ + +extern bool decide_allocation_sampling (void); +extern bool samasan_sampling_init (uint32_t given_sampling_rate); + +#endif /* samasan_sampling.h */ diff --git a/sampling-asan/samasan_variable_init.def b/sampling-asan/samasan_variable_init.def new file mode 100644 index 0000000000..6f43e7d1fd --- /dev/null +++ b/sampling-asan/samasan_variable_init.def @@ -0,0 +1,38 @@ +/* Default values of configurables in sampling-asan. + Copyright (C) 2025 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 + . */ + +#define DEFAULT_SAMASAN_ENABLED "false" +#define DEFAULT_SAMASAN_SAMPLING_RATE "0.005" /* 0.005 */ +#define DEFAULT_SAMASAN_MAX_ALLOC_SIZE "4096" +#define DEFAULT_SAMASAN_MAX_ON_GOING_ALLOCATIONS "100" +#define DEFAULT_SAMASAN_OUTPUT_PATH "stderr" +#define DEFAULT_SAMASAN_PARTITION_SIZE "4096" /* 1 page */ +#define DEFAULT_SAMASAN_PAUSE_ON_FORK "true" +#define DEFAULT_SAMASAN_CHUNK_PICK "CENTER" +#define DEFAULT_SAMASAN_CONTINUE_ON_CRASH "false" + +/* MAX and MIN define a range of the given configuration. */ +#define MAX_SAMASAN_SAMPLING_RATE "100000" +#define MAX_SAMASAN_MAX_ALLOC_SIZE "40960" +#define MAX_SAMASAN_MAX_ON_GOING_ALLOCATIONS "10000" +#define MAX_SAMASAN_PARTITION_SIZE "40960" /* 10 pages */ + +#define MIN_SAMASAN_SAMPLING_RATE "0" +#define MIN_SAMASAN_MAX_ALLOC_SIZE "4096" +#define MIN_SAMASAN_MAX_ON_GOING_ALLOCATIONS "1" +#define MIN_SAMASAN_PARTITION_SIZE "0" /* no partition page */ From patchwork Thu Nov 6 01:44:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123606 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1D49B3854821 for ; Thu, 6 Nov 2025 01:45:47 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout2.samsung.com (mailout2.samsung.com [203.254.224.25]) by sourceware.org (Postfix) with ESMTPS id 2835B38560BC for ; Thu, 6 Nov 2025 01:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2835B38560BC Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2835B38560BC Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.25 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; cv=none; b=NzDsrRgIoxXpHPGvC+2IwbF7+PB+MzoQGqxSXlBQAKqLgjJ7eiLqTnU2gA1doHXCzMLLVw1oQigbbDjYr5R0FWm1mo5yjOs/Zu6rq7ujU5U4vXLtgMXwZ0GPNLYLJs5qleg+UM2VY1fm+vAgcuTkFdFP03jgA3LqHdNwL5bvwnQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; c=relaxed/simple; bh=d2GyqYC/nALp/+TWUAciyBRWnOP43gG7hJK1NF6AiIc=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=GFOktAFLn0Hwso7R/isle7prKeF3Uo0Tf8Nn834DB0OhIiFKBakWfV1gGPOqnxgwl7D0k0gVjUXTRfa1SUU6N+dxTFeMZgK/wpCyPNXwVzwZpn4Wm8eb1mmWnXg3MQ6k8nk20j4l8FgJSIx1tra4vj4XweQFLHJVqWxnt5P2ZxY= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2835B38560BC Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=QR6iNO6j Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp02df6694a2c97c18dd1aa5811071541387~1R4suR01I1981619816epoutp02I for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20251106014452epoutp02df6694a2c97c18dd1aa5811071541387~1R4suR01I1981619816epoutp02I DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=nTOi0uLCdmWberQv6W8BgNSfZZg0YrS/eJDNrRv8JRM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QR6iNO6jE/elpZ/7ExGEQqNLA6mCj5om6UnlC/4GWtlyJtd1ugGjezYOVBMAFaW+B kuKsYdCsn1fb08OZlOT5yR58jLqridbKMgUNnRMvgzVB4Y4t2Zz8mcJD+v2r6YWYk8 UuFi8c4SCVhodjGuKwE8m+zjUAo7G7OV/4DqtFbQ= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPS id 20251106014451epcas1p1be208091da96305460b83e396c7e79b3~1R4sRC32F0552905529epcas1p1U; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epcas1p2.samsung.com (unknown [182.195.38.110]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kW2xQtz3hhT4; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epcas1p38270f69e31de78f6d7153fa23555b462~1R4raeQdg3042130421epcas1p3O; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epsmtip2bac787c72879c856f7cc68247cc378f2~1R4rS8BX32513225132epsmtip2G; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 2/9] debug: Make backtrace_symbols hidden to bypass PLT for Glibc-internal calls Date: Thu, 6 Nov 2025 10:44:19 +0900 Message-Id: <20251106014426.3767818-2-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014450epcas1p38270f69e31de78f6d7153fa23555b462 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014450epcas1p38270f69e31de78f6d7153fa23555b462 References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Signed-off-by: Sung-hun Kim --- debug/backtracesyms.c | 1 + include/execinfo.h | 1 + 2 files changed, 2 insertions(+) diff --git a/debug/backtracesyms.c b/debug/backtracesyms.c index c40b405788..7440dc3897 100644 --- a/debug/backtracesyms.c +++ b/debug/backtracesyms.c @@ -117,3 +117,4 @@ __backtrace_symbols (void *const *array, int size) return result; } weak_alias (__backtrace_symbols, backtrace_symbols) +libc_hidden_def (__backtrace_symbols) diff --git a/include/execinfo.h b/include/execinfo.h index 0b132b089f..12a1a5bd5b 100644 --- a/include/execinfo.h +++ b/include/execinfo.h @@ -7,6 +7,7 @@ extern int __backtrace (void **__array, int __size); libc_hidden_proto (__backtrace) extern char **__backtrace_symbols (void *const *__array, int __size); +libc_hidden_proto (__backtrace_symbols) extern void __backtrace_symbols_fd (void *const *__array, int __size, int __fd); From patchwork Thu Nov 6 01:44:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123613 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B10333857723 for ; Thu, 6 Nov 2025 01:52:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B10333857723 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=VL3C4+JF X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by sourceware.org (Postfix) with ESMTPS id 2B7C5385C6C6 for ; Thu, 6 Nov 2025 01:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2B7C5385C6C6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2B7C5385C6C6 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.24 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; cv=none; b=IEP+UpXSDVBlkx+qsFmcH++1V2QMTx5K2mosxwlL/aigH6pj6RJ/DlNRsOTvSupZfr8gslGSHp962iiWwte7fPVW1jiw5C3VfVrh62kby5jxfFiw83xWy5j7Np//8enEhnLmH9lXCEo4pYNu0UuA29LFqxpG928GCYc0IsbG6g0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; c=relaxed/simple; bh=z0oO7veW7Vj76CdjJznqid5c3LGm5Ns0umUxsPgwg4g=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=iBYqOBTt/4fzh1XqUdCPFnndfZpb3McFWynQU2A8d9fM75j3tGmzK1Oo1sqCwmUXeBXN4WvRBdbaBOgDTg1DDlY9DLoyCzbCE6v5hi1RfqNqqNkUkMgQgK6ZWzA2dQ1pdppMPwYjfLANHla5uXfWxEXg/Z8RmryJoWCQuVEGFoM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2B7C5385C6C6 Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp014645d6722be468dad182c1bb373bd911~1R4s8MnIx2704627046epoutp01b for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20251106014452epoutp014645d6722be468dad182c1bb373bd911~1R4s8MnIx2704627046epoutp01b DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=nGe7RrxTFmG7AgwLMHDm7Ok8z5xwns41SczWZ4rdH3s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VL3C4+JFmag0+9Gq++mHocOCSrkSLBhi9lz3TinyYINw5hvI5mwMrP2At01whvGTi zE2idtIjKLMDo81U1uaOmDsqc4M1F94p22/opvYS88gWLirihBmYxDmL6yP33WNNyA kHasTI5XVzyNbXo50SvYWhfSObKyqNH8aOtUGUFU= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p1e55cafdd4eb1ba72c7e05b8821b5b1c1~1R4spW4LK0845608456epcas1p12; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p2.samsung.com (unknown [182.195.38.103]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kW4LcJz3hhTD; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epcas1p37a307260582115bd127b2064ab6bc33d~1R4rhJ3eB3041730417epcas1p3d; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014450epsmtip2cc9ad4751c126804529650e1076ce7ae~1R4rbI4zt2407324073epsmtip2f; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 3/9] sampling-asan: Add test cases for sampling-asan Date: Thu, 6 Nov 2025 10:44:20 +0900 Message-Id: <20251106014426.3767818-3-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014450epcas1p37a307260582115bd127b2064ab6bc33d X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014450epcas1p37a307260582115bd127b2064ab6bc33d References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Test cases are categorized into two groups: 1. Testing basic functionalities of sampling-asan 2. Testing creation of proper memory bug reports Memory bug types are defined in samasan_error.h. If you wonder about it, please refer the header file. Signed-off-by: Sung-hun Kim --- sampling-asan/Makefile | 61 +++++++ sampling-asan/tst-allocate.c | 209 ++++++++++++++++++++++++ sampling-asan/tst-block-sizes.c | 68 ++++++++ sampling-asan/tst-bypass-block.c | 68 ++++++++ sampling-asan/tst-chunk-pick.c | 106 ++++++++++++ sampling-asan/tst-common.c | 88 ++++++++++ sampling-asan/tst-continue-on-crash.c | 113 +++++++++++++ sampling-asan/tst-double-free.c | 63 +++++++ sampling-asan/tst-init.c | 120 ++++++++++++++ sampling-asan/tst-invalid-access.c | 71 ++++++++ sampling-asan/tst-invalid-access2.c | 66 ++++++++ sampling-asan/tst-invalid-free.c | 65 ++++++++ sampling-asan/tst-invalid-free2.c | 65 ++++++++ sampling-asan/tst-invalid-write.c | 69 ++++++++ sampling-asan/tst-out-of-memory-pool.c | 61 +++++++ sampling-asan/tst-partition-sizes.c | 88 ++++++++++ sampling-asan/tst-pause-on-fork.c | 139 ++++++++++++++++ sampling-asan/tst-sampling.c | 82 ++++++++++ sampling-asan/tst-threaded-allocation.c | 90 ++++++++++ sampling-asan/tst-use-after-free.c | 66 ++++++++ 20 files changed, 1758 insertions(+) create mode 100644 sampling-asan/tst-allocate.c create mode 100644 sampling-asan/tst-block-sizes.c create mode 100644 sampling-asan/tst-bypass-block.c create mode 100644 sampling-asan/tst-chunk-pick.c create mode 100644 sampling-asan/tst-common.c create mode 100644 sampling-asan/tst-continue-on-crash.c create mode 100644 sampling-asan/tst-double-free.c create mode 100644 sampling-asan/tst-init.c create mode 100644 sampling-asan/tst-invalid-access.c create mode 100644 sampling-asan/tst-invalid-access2.c create mode 100644 sampling-asan/tst-invalid-free.c create mode 100644 sampling-asan/tst-invalid-free2.c create mode 100644 sampling-asan/tst-invalid-write.c create mode 100644 sampling-asan/tst-out-of-memory-pool.c create mode 100644 sampling-asan/tst-partition-sizes.c create mode 100644 sampling-asan/tst-pause-on-fork.c create mode 100644 sampling-asan/tst-sampling.c create mode 100644 sampling-asan/tst-threaded-allocation.c create mode 100644 sampling-asan/tst-use-after-free.c diff --git a/sampling-asan/Makefile b/sampling-asan/Makefile index 6f27bbed0d..c23ca65f86 100644 --- a/sampling-asan/Makefile +++ b/sampling-asan/Makefile @@ -44,4 +44,65 @@ install-lib = libsamasan.so install-lib-ldscripts = libsamasan.so $(inst_libdir)/libsamasan.so: +tests := \ + tst-allocate \ + tst-block-sizes \ + tst-bypass-block \ + tst-chunk-pick \ + tst-continue-on-crash \ + tst-double-free tst-init \ + tst-invalid-access \ + tst-invalid-access2 \ + tst-invalid-free \ + tst-invalid-free2 \ + tst-invalid-write \ + tst-out-of-memory-pool \ + tst-partition-sizes \ + tst-pause-on-fork \ + tst-sampling \ + tst-threaded-allocation \ + tst-use-after-free +# tests + +$(objpfx)tst-threaded-allocation: $(shared-thread-library) + +LDLIBS-tst-allocate += -lsamasan +LDLIBS-tst-block-sizes += -lsamasan +LDLIBS-tst-bypass-block += -lsamasan +LDLIBS-tst-chunk-pick += -lsamasan +LDLIBS-tst-continue-on-crash += -lsamasan +LDLIBS-tst-double-free += -lsamasan +LDLIBS-tst-init += -lsamasan +LDLIBS-tst-invalid-access += -lsamasan +LDLIBS-tst-invalid-access2 += -lsamasan +LDLIBS-tst-invalid-free += -lsamasan +LDLIBS-tst-invalid-free2 += -lsamasan +LDLIBS-tst-invalid-write += -lsamasan +LDLIBS-tst-out-of-memory-pool += -lsamasan +LDLIBS-tst-partition-sizes += -lsamasan +LDLIBS-tst-pause-on-fork += -lsamasan +LDLIBS-tst-sampling += -lsamasan +LDLIBS-tst-threaded-allocation += -lsamasan +LDLIBS-tst-use-after-free += -lsamasan + +LDFLAGS-tst-allocate += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-block-sizes += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-bypass-block += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-chunk-pick += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-continue-on-crash += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-double-free += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-init += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-invalid-access += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-invalid-access2 += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-invalid-free += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-invalid-free2 += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-invalid-write += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-out-of-memory-pool += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-partition-sizes += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-pause-on-fork += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-sampling += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-threaded-allocation += -L$(objpfx) -Wl,-rpath-link=$(objpfx) +LDFLAGS-tst-use-after-free += -L$(objpfx) -Wl,-rpath-link=$(objpfx) + + include ../Rules diff --git a/sampling-asan/tst-allocate.c b/sampling-asan/tst-allocate.c new file mode 100644 index 0000000000..6b05956179 --- /dev/null +++ b/sampling-asan/tst-allocate.c @@ -0,0 +1,209 @@ +/* Test and verify allocations in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static void +test_allocations (void) +{ + const size_t zero_size = 0; + const size_t allocation_size = 4096; + void *ptr; + + ptr = samasan_allocate (zero_size); + TEST_VERIFY (ptr == NULL); + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (ptr != NULL); + samasan_free (ptr); +} + +static void +test_too_large_allocation (void) +{ + const size_t allocation_size = 4096 + 4096; + void *ptr; + + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (ptr == NULL); +} + +static void +test_multiple_allocations (void) +{ +#define MAX_ALLOCATIONS 101 + const size_t allocation_size = 512; + void *ptr[MAX_ALLOCATIONS] = { NULL, }; + + for (int i = 0; i < MAX_ALLOCATIONS; i++) + ptr[i] = samasan_allocate (allocation_size); + TEST_VERIFY (ptr[MAX_ALLOCATIONS - 1] == NULL); + for (int i = 0; i < MAX_ALLOCATIONS - 1; i++) + samasan_free (ptr[i]); +#undef MAX_ALLOCATIONS +} + +static void +test_allocation_and_free (void) +{ +#define MAX_ALLOCATIONS 100 + const size_t allocation_size = 512; + void *ptr[MAX_ALLOCATIONS] = { NULL, }; + + for (int i = 0; i < MAX_ALLOCATIONS; i++) + { + ptr[i] = samasan_allocate (allocation_size); + TEST_VERIFY (ptr[i] != NULL); + } + for (int i = 0; i < MAX_ALLOCATIONS; i++) + samasan_free (ptr[i]); + for (int i = 0; i < MAX_ALLOCATIONS; i++) + { + ptr[i] = samasan_allocate (allocation_size); + TEST_VERIFY (ptr[i] != NULL); + } + for (int i = 0; i < MAX_ALLOCATIONS; i++) + samasan_free (ptr[i]); +#undef MAX_ALLOCATIONS +} + +static void +test_allocation_use_free_repeat (void) +{ +#define NR_REPEAT 100 + const size_t allocation_size = 512; + void *ptr; + + for (int i = 0; i < NR_REPEAT; i++) + { + char *cptr; + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (ptr != NULL); + cptr = (char *) ptr; + for (int j = 0; j < allocation_size; j++) + cptr[j] = 'a'; + samasan_free (ptr); + } +#undef NR_REPEAT +} + +static void +test_out_of_bound_pointer (void) +{ +#define OUT_OF_BOUND_OFFSET (4096 * 100) + const size_t allocation_size = 512; + void *ptr, *oob_ptr; + + ptr = samasan_allocate (allocation_size); + oob_ptr = ptr + OUT_OF_BOUND_OFFSET; + TEST_VERIFY (samasan_is_pointer_in_sampling_pool (oob_ptr) == false); + samasan_free (ptr); +#undef OUT_OF_BOUND_OFFSET +} + +static void +test_allocated_size (void) +{ + const size_t allocation_size1 = 512; + const size_t allocation_size2 = 1023; + void *ptr1, *ptr2; + + ptr1 = samasan_allocate (allocation_size1); + ptr2 = samasan_allocate (allocation_size2); + + TEST_VERIFY (samasan_get_size (ptr1) == allocation_size1); + TEST_VERIFY (samasan_get_size (ptr2) == allocation_size2); + + samasan_free (ptr1); + samasan_free (ptr2); +} + +static void +test_wrong_get_size (void) +{ +#define OUT_OF_BOUND_OFFSET (4096 * 100) + const size_t allocation_size = 512; + void *ptr, *oob_ptr; + + ptr = samasan_allocate (allocation_size); + oob_ptr = ptr + OUT_OF_BOUND_OFFSET; + + TEST_VERIFY (samasan_get_size (ptr) == allocation_size); + /* the size of out-of-bound memory chunk should be zero */ + TEST_VERIFY (samasan_get_size (oob_ptr) == 0); + + samasan_free (ptr); + + /* the size of freed chunk should be zero */ + TEST_VERIFY (samasan_get_size (ptr) == 0); +#undef OUT_OF_BOUND_OFFSET +} + +static inline bool +is_aligned (uintptr_t address) +{ + return (address % sizeof (size_t)) == 0; +} + +static void +test_aligned_allocation (void) +{ + const size_t allocation_size = 512; + void *ptr; + + for (size_t i = 0; i < 100; i++) + { + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (is_aligned ((uintptr_t) ptr)); + samasan_free(ptr); + } +} + +static int +do_test (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1/* replace */); + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + /* allocation tests */ + test_allocations(); + test_too_large_allocation (); + test_multiple_allocations (); + test_allocation_and_free (); + test_allocation_use_free_repeat (); + + /* allocation sanity checking tests */ + test_out_of_bound_pointer (); + test_allocated_size (); + test_wrong_get_size (); + test_aligned_allocation (); + + return 0; +} + +#include diff --git a/sampling-asan/tst-block-sizes.c b/sampling-asan/tst-block-sizes.c new file mode 100644 index 0000000000..274a3a8c5e --- /dev/null +++ b/sampling-asan/tst-block-sizes.c @@ -0,0 +1,68 @@ +/* Test and verify various chunk sizes in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static void +test_multiple_chunk_sizes (size_t size) +{ + void *ptr; + char *cptr; + char chunk_size[10]; + const size_t increase = 64; + size_t allocation_size = increase; + + sprintf (chunk_size, "%ld", size); + setenv ("SAMASAN_MAX_ALLOC_SIZE", chunk_size, 1/* replace */); + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == true); + for (; allocation_size <= size; allocation_size += increase) + { + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (ptr != NULL); + cptr = (char *) ptr; + *cptr = 'A'; + samasan_free (ptr); + } + samasan_deinit (); +} + +static int +do_test (void) +{ + const size_t page_size = 4096; + + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + + for (size_t i = 1; i < 10; i++) + test_multiple_chunk_sizes (page_size * i); + + return 0; +} + +#include diff --git a/sampling-asan/tst-bypass-block.c b/sampling-asan/tst-bypass-block.c new file mode 100644 index 0000000000..3dcacc58af --- /dev/null +++ b/sampling-asan/tst-bypass-block.c @@ -0,0 +1,68 @@ +/* Test and verify a double-free case. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static void +do_use_after_free_iteration (size_t iterations) +{ + size_t allocation_size = 512; + int *ptr; + + for (size_t i = 0; i < iterations; i++) + { + ptr = (int *) samasan_allocate (allocation_size); + *(ptr) = 1; + samasan_free (ptr); + *(ptr) = 0; /* raise use-after-free */ + printf ("%ld\n", i); + } + + ptr = (int *) samasan_allocate (allocation_size); + TEST_VERIFY (ptr == NULL); /* memory pool exhausted */ +} + +static int +do_test (void) +{ + const char *report_path = "/dev/null"; + + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1/* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1/* replace */); + setenv ("SAMASAN_CONTINUE_ON_CRASH", "true", 1/* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + do_use_after_free_iteration (10); + + return 0; +} + +#include diff --git a/sampling-asan/tst-chunk-pick.c b/sampling-asan/tst-chunk-pick.c new file mode 100644 index 0000000000..bdeed87c92 --- /dev/null +++ b/sampling-asan/tst-chunk-pick.c @@ -0,0 +1,106 @@ +/* Test and verify memory chunk pick styles defined in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ +#include "samasan_allocate.h" /* for memory_chunk_pick_style_t */ + +static const size_t page_size = 4096; + +static bool +check_allocation_align +(memory_chunk_pick_style_t style, size_t size, void *ptr) +{ + uintptr_t address = (uintptr_t) ptr; + uintptr_t page_address = address - (address % page_size); + + if (style == PICK_FROM_LEFT) + { + /* If style == PICK_FROM_LEFT, the address should be same to + * the address of the memory block. */ + if (address == page_address) + return true; + return false; + } + else if (style == PICK_FROM_RIGHT) + { + /* If style == PICK_FROM_RIGHT, the end of the memory chunk should be + * same to the end of the memory block. */ + if (address == (page_address + page_size - size)) + return true; + return false; + } + else /* style == PICK_CENTER */ + { + /* If style == PICK_CENTER, the address should be located at the + center of the memory block. */ + uintptr_t expected = page_address + ((page_size - size) >> 1); + if (address == expected) + return true; + return false; + } + return false; +} + +static void +test_memory_chunk_pick_style (memory_chunk_pick_style_t style) +{ + const size_t alloc_size = 512; + void *ptr; + + if (style == PICK_FROM_LEFT) + setenv ("SAMASAN_CHUNK_PICK", "LEFT", 1); + else if (style == PICK_FROM_RIGHT) + setenv ("SAMASAN_CHUNK_PICK", "RIGHT", 1); + else + setenv ("SAMASAN_CHUNK_PICK", "CENTER", 1); + + samasan_init (); + + ptr = samasan_allocate (alloc_size); + TEST_VERIFY (ptr != NULL); + TEST_VERIFY (check_allocation_align (style, alloc_size, ptr)); + samasan_free (ptr); + + samasan_deinit (); +} + +static int +do_test (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + + for (memory_chunk_pick_style_t style = PICK_FROM_LEFT; + style < PICK_END; + style++) + test_memory_chunk_pick_style (style); + + return 0; +} + +#include diff --git a/sampling-asan/tst-common.c b/sampling-asan/tst-common.c new file mode 100644 index 0000000000..6da4fc5ee4 --- /dev/null +++ b/sampling-asan/tst-common.c @@ -0,0 +1,88 @@ +/* Definition of common functions for testing. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include + +static bool +check_report (const char *keyword, const char *report_path) +{ + if (access (report_path, F_OK) == 0) + { + bool check = false; + FILE *report = fopen (report_path, "r"); + if (report != NULL) + { + char buf[255], *substr; + while (fscanf (report, "%s", buf) != EOF) + { + substr = strstr (buf, keyword); + if (substr != NULL && !strncmp (substr, keyword, strlen (keyword))) + { + check = true; + break; + } + memset (buf, 0, sizeof (buf)); + } + fclose (report); + } + return (check == true); + } + return false; +} + +static bool +wait_error (pid_t child_pid) +{ + int status; + waitpid (child_pid, &status, 0); + return WIFSIGNALED (status) && (WTERMSIG (status) == SIGSEGV); +} + +static void +clean_up_report (const char *report_path) +{ + if (access (report_path, F_OK) == 0) + unlink (report_path); +} + +static void +test_bed (void (*error_func) (void), const char *keyword, + const char *report_path) +{ + pid_t child_pid; + + clean_up_report (report_path); + + child_pid = _Fork (); + TEST_VERIFY_EXIT (child_pid != -1); + + if (child_pid == 0) + error_func (); + else + { + TEST_VERIFY_EXIT (wait_error (child_pid) == true); + TEST_VERIFY (check_report (keyword, report_path) == true); + } + + clean_up_report (report_path); +} diff --git a/sampling-asan/tst-continue-on-crash.c b/sampling-asan/tst-continue-on-crash.c new file mode 100644 index 0000000000..9fc3b407eb --- /dev/null +++ b/sampling-asan/tst-continue-on-crash.c @@ -0,0 +1,113 @@ +/* Test and verify an invalid-access case. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static bool continue_after_crash = false; + +static bool +check_report (const char *keyword, const char *report_path) +{ + printf ("%s\n", report_path); + if (access (report_path, F_OK) == 0) + { + printf ("access success\n"); + bool check = false; + FILE *report = fopen (report_path, "r"); + if (report != NULL) + { + char buf[255], *substr; + while (fscanf (report, "%s", buf) != EOF) + { + substr = strstr (buf, keyword); + if (substr != NULL && !strncmp (substr, keyword, strlen (keyword))) + { + check = true; + break; + } + memset (buf, 0, sizeof (buf)); + } + fclose (report); + } + return (check == true); + } + printf ("access failed\n"); + return false; +} + +static void +clean_up_report (const char *report_path) +{ + if (access (report_path, F_OK) == 0) + unlink (report_path); +} + +static void +test_use_after_free_continue (void) +{ + const size_t allocation_size = 512; + int *ptr; + + ptr = (int *) samasan_allocate (allocation_size); + *(ptr) = 1; + samasan_free (ptr); + *(ptr) = 0; /* raise use-after-free */ + + continue_after_crash = true; +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/continue-on-crash-report"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + setenv ("SAMASAN_CONTINUE_ON_CRASH", "on", 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_use_after_free_continue (); + + TEST_VERIFY (check_report ("USE_AFTER_FREE", report_path) == true); + clean_up_report (report_path); + + /* We set SAMASAN_CONTINUE_ON_CRASH to "on", so the thread should + run even after a crash occurred. */ + TEST_VERIFY (continue_after_crash == true); + + return 0; +} + +#include diff --git a/sampling-asan/tst-double-free.c b/sampling-asan/tst-double-free.c new file mode 100644 index 0000000000..c7a96cb1f6 --- /dev/null +++ b/sampling-asan/tst-double-free.c @@ -0,0 +1,63 @@ +/* Test and verify a double-free case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_double_free (void) +{ + const size_t allocation_size = 512; + void *ptr; + + ptr = samasan_allocate (allocation_size); + samasan_free (ptr); + samasan_free (ptr); /* raise segmentation fault */ +} + +static void test_double_free (const char *report_path) +{ + test_bed (do_double_free, "DOUBLE_FREE", report_path); +} + +static int do_test (void) +{ + const char *report_path = "/tmp/double-free-error-report"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_double_free (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-init.c b/sampling-asan/tst-init.c new file mode 100644 index 0000000000..d818e0d307 --- /dev/null +++ b/sampling-asan/tst-init.c @@ -0,0 +1,120 @@ +/* Test and verify initialization in sampling-asan + Copyright (C) 2025 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 + . */ + +#include +#include + +#include + +#include "samasan.h" +#include "samasan_init.h" + +static void +test_repeated_init_and_deinit (void) +{ +#define REPEATS 100 + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + + for (int i = 0; i < REPEATS; i++) + { + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == true); + samasan_deinit (); + TEST_VERIFY (samasan_is_enabled () == false); + } +#undef REPEATS +} + +static void +test_misconfigurations (void) +{ + setenv ("SAMASAN_ENABLE", + "truth" /* should be "yes" or "true" or "enable" or "on" */, + 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096" /* exceed the upper limit */, + 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == false); + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "409600" /* exceed the upper limit */, + 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == false); + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", + "100000" /* exceed the upper limit */, 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == false); + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.2" /* exceed 100% */, 1 /* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == false); +} + +static void +test_multiple_inits (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096" /* exceed the upper limit */, + 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == true); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == true); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled () == true); + + samasan_deinit (); + TEST_VERIFY (samasan_is_enabled () == false); +} + +static int +do_test (void) +{ + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + + test_repeated_init_and_deinit (); + test_misconfigurations (); + test_multiple_inits (); + + return 0; +} + +#include diff --git a/sampling-asan/tst-invalid-access.c b/sampling-asan/tst-invalid-access.c new file mode 100644 index 0000000000..6863740a61 --- /dev/null +++ b/sampling-asan/tst-invalid-access.c @@ -0,0 +1,71 @@ +/* Test and verify an invalid-access case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_invalid_access (void) +{ + const size_t allocation_size = 512; + void *ptr; + char *cptr; + + ptr = samasan_allocate (allocation_size); + /* The sampling memory pool tends to allocate a memory chunk from + the tail of the memory pool for the first allocation. Because of + that, an access to the increased address from the pointer causes + an undefined behavior since it reaches beyond the memory pool. + So, just use the decreased address for here. */ + cptr = (char *) ptr - 4096 * 2; // One page for partition + *cptr = 'A'; /* an invalid access occurred! */ +} + +static void +test_invalid_access (const char *report_path) +{ + test_bed (do_invalid_access, "INVALID_ACCESS", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/invalid-access-error-report"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_invalid_access (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-invalid-access2.c b/sampling-asan/tst-invalid-access2.c new file mode 100644 index 0000000000..a73c317fdf --- /dev/null +++ b/sampling-asan/tst-invalid-access2.c @@ -0,0 +1,66 @@ +/* Test and verify an unaligned-access case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_invalid_access (void) +{ + const size_t allocation_size = 512; + void *ptr; + char *cptr; + + ptr = samasan_allocate (allocation_size); + cptr = (char *) ptr + 4096; + *cptr = 'A'; /* an invalid access occurred! */ +} + +static void +test_invalid_access (const char *report_path) +{ + test_bed (do_invalid_access, "INVALID_ACCESS", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/invalid-access-error-report2"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "12288", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_invalid_access (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-invalid-free.c b/sampling-asan/tst-invalid-free.c new file mode 100644 index 0000000000..e3c2d30fee --- /dev/null +++ b/sampling-asan/tst-invalid-free.c @@ -0,0 +1,65 @@ +/* Test and verify an invalid-free case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_invalid_free (void) +{ + void *ptr; + const size_t allocation_size = 512; + + ptr = samasan_allocate (allocation_size); + ptr += 512; + samasan_free (ptr); /* invalid free error occurred */ +} + +static void +test_invalid_free (const char *report_path) +{ + test_bed (do_invalid_free, "INVALID_FREE", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/invalid-free-error-report"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_invalid_free (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-invalid-free2.c b/sampling-asan/tst-invalid-free2.c new file mode 100644 index 0000000000..9a273204d7 --- /dev/null +++ b/sampling-asan/tst-invalid-free2.c @@ -0,0 +1,65 @@ +/* Test and verify an invalid-free case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_invalid_free (void) +{ + void *ptr; + const size_t allocation_size = 512; + + ptr = samasan_allocate (allocation_size); + ptr -= 512; + samasan_free (ptr); /* invalid free error occurred */ +} + +static void +test_invalid_free (const char *report_path) +{ + test_bed (do_invalid_free, "INVALID_FREE", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/invalid-free-error-report2"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_invalid_free (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-invalid-write.c b/sampling-asan/tst-invalid-write.c new file mode 100644 index 0000000000..404f870e98 --- /dev/null +++ b/sampling-asan/tst-invalid-write.c @@ -0,0 +1,69 @@ +/* Test and verify allocations in sampling-asan. + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_invalid_write (void) +{ + size_t allocation_size = 512; + void *ptr; + char *cptr; + + ptr = samasan_allocate (allocation_size); + TEST_VERIFY (ptr != NULL); + cptr = (char *) ptr; + *(cptr + allocation_size) = 'a'; + samasan_free (ptr); /* error occurred! */ +} + +static void +test_invalid_write (const char *report_path) +{ + test_bed (do_invalid_write, "INVALID_WRITE", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/invalid-write-error-report"; + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "8192", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1/* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + /* invalid-write tests */ + test_invalid_write (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-out-of-memory-pool.c b/sampling-asan/tst-out-of-memory-pool.c new file mode 100644 index 0000000000..9ce44f8287 --- /dev/null +++ b/sampling-asan/tst-out-of-memory-pool.c @@ -0,0 +1,61 @@ +/* Test and verify an out-of-memory-pool case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_out_of_memory_pool (void) +{ + char *cptr = (char *) 0; + *cptr = 'A'; /* an out-of-memory-pool fault occurred! */ +} + +static void +test_out_of_memory_pool (const char *report_path) +{ + test_bed (do_out_of_memory_pool, "OUT_OF_MEMORY_POOL", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/out-of-memory-pool-error-report"; + + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "1", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1 /* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_out_of_memory_pool (report_path); + + return 0; +} + +#include diff --git a/sampling-asan/tst-partition-sizes.c b/sampling-asan/tst-partition-sizes.c new file mode 100644 index 0000000000..f983d9b686 --- /dev/null +++ b/sampling-asan/tst-partition-sizes.c @@ -0,0 +1,88 @@ +/* Test and verify configurable partition size in sampling-asan + Copyright (C) 2025 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 + . */ + +#include +#include + +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" + +static void +test_partition_size (size_t partition_size) +{ + char buf[100]; + const size_t allocation_size = 512; + void *ptr[10]; + char *cptr; + + sprintf (buf, "%ld", partition_size); + setenv ("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); + + samasan_init (); + TEST_VERIFY (samasan_is_enabled ()); + for (size_t i = 0; i < 10; i++) + { + ptr[i] = samasan_allocate (allocation_size); + TEST_VERIFY (ptr[i] != NULL); + cptr = (char *) ptr[i]; + memset (cptr, 'A' + i, allocation_size); + } + for (size_t i = 0; i < 10; i++) + samasan_free (ptr[i]); + samasan_deinit (); +} + +static void +test_wrong_partition_size (size_t partition_size) +{ + char buf[100]; + + sprintf (buf, "%ld", partition_size); + setenv ("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); + + samasan_init (); + TEST_VERIFY (!samasan_is_enabled ()); +} + +static int +do_test (void) +{ + const size_t page_size = 4096; + + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + + for (size_t i = 0; i <= 10; i++) + test_partition_size (page_size * i); + + test_wrong_partition_size (-1); + test_wrong_partition_size (page_size * 11); + + return 0; +} + +#include diff --git a/sampling-asan/tst-pause-on-fork.c b/sampling-asan/tst-pause-on-fork.c new file mode 100644 index 0000000000..e0a1c7310c --- /dev/null +++ b/sampling-asan/tst-pause-on-fork.c @@ -0,0 +1,139 @@ +/* Test and verify the pause-on-fork feature. + This is implemented by pthread_atfork (internally, __register_atfork). + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static bool thread_ready = false; +static pthread_mutex_t mutex; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +static inline void +thread_get_ready (void) +{ + xpthread_mutex_lock (&mutex); + thread_ready = true; + xpthread_cond_signal (&cond); + xpthread_mutex_unlock (&mutex); +} + +static void* +memory_pool_stay_pause (void* dummy) +{ + thread_get_ready (); + return NULL; +} + +static void* +memory_pool_enable (void* dummy) +{ + thread_get_ready (); + sleep (1); + samasan_memory_pool_resume (); + return NULL; +} + +static void +test_pthread_fork (bool memory_pool_resume) +{ + pid_t pid; + pthread_t thread_id; + + if (memory_pool_resume) + thread_id = xpthread_create (NULL, &memory_pool_enable, NULL); + else + thread_id = xpthread_create (NULL, &memory_pool_stay_pause, NULL); + + xpthread_mutex_lock (&mutex); + while (!thread_ready) + xpthread_cond_wait (&cond, &mutex); + xpthread_mutex_unlock (&mutex); + + if (!memory_pool_resume) + alarm (1); + samasan_memory_pool_pause (); + pid = fork (); + + if (pid == 0) + _exit (0); + + /* If memory_pool_enable == false, never reached here. + The process will be terminated by the alarm call. */ + waitpid (pid, NULL, 0); + xpthread_join (thread_id); +} + +static void +test_bed (bool memory_pool_resume) +{ + pid_t pid; + int ret; + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + xpthread_mutex_init (&mutex, NULL); + thread_ready = false; + + pid = fork (); + if (pid == 0) + { + test_pthread_fork (memory_pool_resume); + _exit (0); + } + + waitpid (pid, &ret, 0); + if (memory_pool_resume) + { + TEST_VERIFY (WIFEXITED (ret)); + TEST_COMPARE (WTERMSIG (ret), 0); + } + else + { + TEST_VERIFY (WIFSIGNALED (ret)); + TEST_COMPARE (WTERMSIG (ret), SIGALRM); + } +} + +static int +do_test (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + setenv ("SAMASAN_PAUSE_ON_FORK", "true", 1 /* replace */); + + test_bed (false /* memory_pool_resume */); + test_bed (true /* memory_pool_resume */); + + return 0; +} + +#include diff --git a/sampling-asan/tst-sampling.c b/sampling-asan/tst-sampling.c new file mode 100644 index 0000000000..f7c7db7858 --- /dev/null +++ b/sampling-asan/tst-sampling.c @@ -0,0 +1,82 @@ +/* Test and verify sampling methods in sampling-asan + Copyright (C) 2025 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 + . */ + +#include +#include +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +static void +test_sampling_on_uninited (void) +{ + const size_t allocation_size = 512; + + TEST_VERIFY (samasan_sampling_ok (allocation_size) == false); +} + +static void +test_sampling (void) +{ + const size_t allocation_size = 512; + const size_t large_allocation_size = 4097; + + TEST_VERIFY (samasan_sampling_ok (allocation_size) == true); + TEST_VERIFY (samasan_sampling_ok (large_allocation_size) == false); +} + +static void +test_sampling_exhausted (void) +{ +#define MAX_ALLOCATIONS 10 + const size_t allocation_size = 512; + void *ptr[MAX_ALLOCATIONS] = {NULL,}; + + for (int i = 0; i < MAX_ALLOCATIONS; i++) + ptr[i] = samasan_allocate (allocation_size); + TEST_VERIFY (samasan_sampling_ok (allocation_size) == false); + + for (int i = 0; i < MAX_ALLOCATIONS; i++) + samasan_free (ptr[i]); + TEST_VERIFY (samasan_sampling_ok (allocation_size) == true); +#undef MAX_ALLOCATIONS +} + +static int +do_test (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + test_sampling_on_uninited (); + + samasan_init (); + + test_sampling (); + test_sampling_exhausted (); + + return 0; +} + +#include diff --git a/sampling-asan/tst-threaded-allocation.c b/sampling-asan/tst-threaded-allocation.c new file mode 100644 index 0000000000..77871245c6 --- /dev/null +++ b/sampling-asan/tst-threaded-allocation.c @@ -0,0 +1,90 @@ +/* Test and verify threaded-allocations in sampling-asan + Copyright (C) 2025 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 + . */ + +#include +#include +#include + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#define MAX_ON_GOING_ALLOCATIONS 100 +#define MAX_THREADS 10 +static int allocations_per_thread = MAX_ON_GOING_ALLOCATIONS / MAX_THREADS; +static int thread_id; +static void *global_ptr[MAX_ON_GOING_ALLOCATIONS] = { NULL, }; + +static void * +allocation_thread_func (void *data) +{ + int id = __atomic_fetch_add (&thread_id, 1, __ATOMIC_SEQ_CST); + + for (int i = 0; i < allocations_per_thread; i++) + { + global_ptr[id * MAX_THREADS + i] = samasan_allocate (sizeof (int)); + TEST_VERIFY (global_ptr[id * MAX_THREADS + i] != NULL); + } + + return NULL; +} + +static void +test_multi_threaded_allocation (void) +{ + pthread_t *threads = xcalloc (sizeof (pthread_t), MAX_THREADS); + void *ptr; + + thread_id = 0; + + for (int i = 0; i < MAX_THREADS; i++) + threads[i] = xpthread_create (NULL, allocation_thread_func, NULL); + + for (int i = 0; i < MAX_THREADS; i++) + xpthread_join (threads[i]); + ptr = samasan_allocate (sizeof (int)); + TEST_VERIFY (ptr == NULL); + + for (int i = 0; i < MAX_ON_GOING_ALLOCATIONS; i++) + { + samasan_free (global_ptr[i]); + global_ptr[i] = NULL; + } + free (threads); +} + +static int +do_test (void) +{ + setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1 /* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_multi_threaded_allocation (); + + return 0; +} + +#include diff --git a/sampling-asan/tst-use-after-free.c b/sampling-asan/tst-use-after-free.c new file mode 100644 index 0000000000..cdc27786d6 --- /dev/null +++ b/sampling-asan/tst-use-after-free.c @@ -0,0 +1,66 @@ +/* Test and verify a double-free case. + Copyright (C) 2025 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 + . */ + +#include +#include + +#include "samasan.h" +#include "samasan_init.h" /* for samasan_deinit */ + +#include "tst-common.c" + +static void +do_use_after_free (void) +{ + size_t allocation_size = 512; + int *ptr; + + ptr = (int *) samasan_allocate (allocation_size); + *(ptr) = 1; + samasan_free (ptr); + *(ptr) = 0; /* raise use-after-free */ +} + +static void +test_use_after_free (const char *report_path) +{ + test_bed (do_use_after_free, "USE_AFTER_FREE", report_path); +} + +static int +do_test (void) +{ + const char *report_path = "/tmp/use-after-free-error-report"; + + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096", 1/* replace */); + setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "10", 1/* replace */); + setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1/* replace */); + setenv ("SAMASAN_OUTPUT_PATH", report_path, 1/* replace */); + + /* glibc already initialized sampling-asan. + So, deinitialize sampling-asan before starting the test */ + samasan_deinit (); + samasan_init (); + + test_use_after_free (report_path); + + return 0; +} + +#include From patchwork Thu Nov 6 01:44:21 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123605 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F242A385417A for ; Thu, 6 Nov 2025 01:45:45 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) by sourceware.org (Postfix) with ESMTPS id 27E653857723 for ; Thu, 6 Nov 2025 01:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 27E653857723 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 27E653857723 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; cv=none; b=Jy1Aax0fAN5dDPms8L5EBqyjMPGPbfinv9O147wXMbE3uCFBKXjc6mE9TlnZcdopj42ayWiW90GSx93nAS679D88pmi8X+PWJ/lT18NfUAuFfTnksSQwmRxuYxohkEGJ/s0Qcp6Nq7x93w+LkE7d+wqs7h3ZRlYJhFll1XVbZmU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; c=relaxed/simple; bh=pbr5YJF0arQuEIrTYuHAqk/9Qo2yMtusiKVsrZpVepU=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=BckQhb67rxHNsjW4kzY8Camh6Wl0g1T8AAPWMSjWcBTD0HUbE6jXupFGeV9g2CvTDKA/mo/tUroGiKKv92Tc+dvAv7TVL7TW1MiMJ7Vmf6iXv48XmTonWi737RwSHnkppC5gafJfIwVk3WoS5lWB4s5rZgZFqAEZsAmQ4vc0X90= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 27E653857723 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=Bz15pVsD Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp0402ef8ff03945299eee90b2d1256cc0c9~1R4tGfVVO3182031820epoutp04k for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20251106014452epoutp0402ef8ff03945299eee90b2d1256cc0c9~1R4tGfVVO3182031820epoutp04k DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=TxRzTmPKPqeqpltu7yUfuKnhFtv9tWHNuoJsea3k+JA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Bz15pVsDffFSSL8X8u4PtZ/FVUhGmbrgNiG8B/ST+dtqfsyhjK6nDq3I85A3dUZA+ aqUBNdsStZf3LqtUQ/VhTWvo4r8LpGaMPsBSEo1zpUNO8b2J/BS5UNIGdYMMXRnFQ0 PdOR8qAwrh/JRssYBxpReDUm3z7P1DNr1Gh/mjzU= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p1c7658c58e9859eed29007d958b71b87c~1R4ssd7RQ0845608456epcas1p14; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p3.samsung.com (unknown [182.195.38.98]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kW53DWz3hhTC; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p3d8d556bb2db7c625905dbf640d53578c~1R4rnFAcR3041730417epcas1p3m; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip2dac75f9a357ba494cb815f1014e705c6~1R4rhkG5o2513225132epsmtip2H; Thu, 6 Nov 2025 01:44:50 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 4/9] sampling-asan: Add README.md Date: Thu, 6 Nov 2025 10:44:21 +0900 Message-Id: <20251106014426.3767818-4-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p3d8d556bb2db7c625905dbf640d53578c X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p3d8d556bb2db7c625905dbf640d53578c References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, MEDICAL_SUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Signed-off-by: Sung-hun Kim --- sampling-asan/README.md | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 sampling-asan/README.md diff --git a/sampling-asan/README.md b/sampling-asan/README.md new file mode 100644 index 0000000000..b45f6f9112 --- /dev/null +++ b/sampling-asan/README.md @@ -0,0 +1,97 @@ +# Sampling-based address sanitization (sampling-asan) + +Author: Sung-hun Kim (sfoon.kim@samsung.com, sebuns@gmail.com) + +Date: 2025.02.24 +Updated: 2025.09.12 + +## Overview + +A sampling-asan module provides sampling-based address sanitization. +Sampling-asan is highly inspired by [LLVM's gwp-asan](https://llvm.org/docs/GwpAsan.html). +A memory allocation is sampled based on the sampling rate predefined +by the user (or default). Each sampled memory allocation is tracked, +and if a memory bug occurs in the tracked memory area, sampling-asan +generates a bug report at the user defined path (by default, stderr). +In this document, and all sampling-asan source codes, a prefix "samasan" +is used to represent sampling-asan. + +## Preallocated memory pool + +Sampling-asan uses a preallocated memory pool to track memory +allocation. The sizes of the memory pool and a memory block in the +memory pool can be configured by environmental variables (see the +"Configurable" section). Two memory blocks in the memory pool are +separated by an area, namely a partition. Access to the partition is +prohibited. + +An area which is practically allocated to the user is called a memory +chunk. Normally, the user is allowed to access only a memory chunk. +However, due to the constraint of memory management in the kernel, +memory bugs may not be detected even if it accesses areas outside the +memory chunk. But, if the area is modified, it can be detected on the +free call. + +## Memory bugs + +Memory bugs which can be detected sampling-asan are listed below. + +- **INVALID_FREE**: The program tries to free an area that was not allocated before. +- **DOUBLE_FREE**: The program tries to free a memory chunk that has already been freed. +- **USE_AFTER_FREE**: The program tries to access a freed chunk. +- **INVALID_ACCESS**: The program tries to access a prohibited area (e.g., partition). +- **INVALID_WRITE**: The area outside the memory chunk is modified. +- **OUT_OF_MEMORY_POOL**: An error occurrs outside the memory pool. + +## Configurables + +Sampling-asan configures sanitization configuration using environmental +variables. Below is a list of configurables and their default values. + +- **SAMASAN_ENABLE=false**: It indicates whether the program uses sampling-asan or not. +- **SAMASAN_SAMPLING_RATE=0.005**: It represents the sampling-rate used by sampling-asan. +It can have a value between 0.0 and 1.0. +- **SAMASAN_MAX_ON_GOING_ALLOCATIONS=100**: It means the maximum number of concurrent allocations. +- **SAMASAN_MAX_ALLOC_SIZE=4096**: It means the maximum size of each allocation. +An allocation can occupy up to 40,960 bytes. +- **SAMASAN_OUTPUT_PATH=stderr**: It indicates the path of a bug report created when a memory bug occurs. +- **SAMASAN_PARTITION_SIZE=4096**: It represents the size of a boundary area between two memory blocks. +Sampling-asan cannot use this area for allocations. +- **SAMASAN_PAUSE_ON_FORK=true**: Sampling-asan synchronizes the memory pool when a child process is forked +if this variable is true. +- **SAMASAN_CHUNK_PICK=CENTER**: It indicates the picking tendency when allocating a memory chunk from a +memory block. Sampling-asan supports LEFT, RIGHT, and CENTER picking +tendencies. +- **SAMASAN_CONTINUE_ON_CRASH=true**: It indicates to restore the running context from the memory bug catched by +sampling-asan. So, the application keeps run while it gets a bug report. + +When the SAMASAN_CONTINUE_ON_CRASH option is enabled, the application continues running even after a memory bug is detected. However, the preallocated memory pool can be exhausted if bugs are reported continuously. +In such cases, additional memory bugs won't be able to be reported anymore while the application continues running. + +## How to use sampling-asan + +Since sampling-asan is provided as an independent library, the program should be compiled with -lsamasan. +Then, you should use libc_malloc_debug.so if you want to run the program with sampling-asan. + +Run the program with sampling-asan using default configuration: + + $ export LD_PRELOAD=/usr/lib/libc_malloc_debug.so.0 + $ export MALLOC_SANITIZE_=sampling-asan + $ export SAMASAN_ENABLE=true + $ ./run_my_code + +Or, + + $ export LD_PRELOAD=/usr/lib/libc_malloc_debug.so.0 + $ export MALLOC_SANITIZE_=samasan + $ export SAMASAN_ENABLE=true + $ ./run_my_code + +In order to set the custom sampling-rate (e.g., using 0.01): + + $ SAMASAN_SAMPLING_RATE=0.01 ./run_my_code + +In order to set the report path to /path/to/error-report.txt + + $ SAMASAN_OUTPUT_PATH=/path/to/error-report.txt ./run_my_code + From patchwork Thu Nov 6 01:44:22 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123611 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F3BDA3854809 for ; Thu, 6 Nov 2025 01:50:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F3BDA3854809 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=Z0yzGDd5 X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by sourceware.org (Postfix) with ESMTPS id 2BCDB3854809 for ; Thu, 6 Nov 2025 01:44:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2BCDB3854809 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2BCDB3854809 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.24 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393499; cv=none; b=Qe0IYikcVYB0gtuspAqOzWxYokjpNkq+TF7YEbUXYUar1Ti+jNoeYrF/4O+TmGhznqEk/k9NHtr5sjXuBTZJj30TP+ytlJT3lZV+qu2yeZs7Ehkk2Ad+N05E46dH4diZjB/oQQZwvC8w8xeURn89zwz84iVxnBtq/rVZ6mh8iO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393499; c=relaxed/simple; bh=17bhiz8nuFIPeLRgkbGLigFTLAGjAyHMIWOmPU24J7s=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=QJQzufNYcOCHrluL9ISfXEHQ8zTr1lJJYiDeeMvJ+3PDUIp98lgb2D0T4gWSIo8wSRTzXuS1YX4wmIwN1b+Z9WEYUskxNyrNrThZXd1Iuj9NaQBNYrW4uuYE+C+GVolgVSct2j8EXE0+QPMDHUerKPA2/qDFC5F42RKTRLxbzjQ= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp01df57d3d072b19b64323a2f0429006e35~1R4tIinZ62704327043epoutp01d for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20251106014452epoutp01df57d3d072b19b64323a2f0429006e35~1R4tIinZ62704327043epoutp01d DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=bzf4r5RPll2FgLsgbDF8Hb31WYBO0fnFObKz024VTAk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z0yzGDd51qh9Dj4E7ZzY+SfJJ8WaKfywAmK/OkmSz2NQDVSKebHiYoOCL7xnF4pET rcE8vajL5tSlFhPY4cN51FrC688kj3+YyEJKyC3GQobhsdPUqsDBvWnF41e48FApVc bwqw4L5L3YeuJkQ984OloaebkUNtbgdov6sYfHEA= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p2e82c8c73d4b69c69a69335568abf1cf4~1R4swnPkf0781707817epcas1p2I; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.111]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4d24kW5Swwz6B9m7; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p26b4a33bf2674f7107642b136eb0e2a00~1R4rtVy_G0565105651epcas1p2k; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip2b2f4b8e4dd40795c96660ef1e368918c~1R4rnvvgi2008820088epsmtip2X; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 5/9] Makeconfig: Add a sampling-asan directory to the build script Date: Thu, 6 Nov 2025 10:44:22 +0900 Message-Id: <20251106014426.3767818-5-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p26b4a33bf2674f7107642b136eb0e2a00 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p26b4a33bf2674f7107642b136eb0e2a00 References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Signed-off-by: Sung-hun Kim --- Makeconfig | 10 ++++++++-- shlib-versions | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Makeconfig b/Makeconfig index eb44bbd113..f028e2b1c8 100644 --- a/Makeconfig +++ b/Makeconfig @@ -637,7 +637,7 @@ link-libc-printers-tests = $(link-libc-rpath) \ $(link-libc-tests-after-rpath-link) # This is how to find at build-time things that will be installed there. -rpath-dirs = math elf dlfcn nss nis rt resolv mathvec support misc debug +rpath-dirs = math elf dlfcn nss nis rt resolv mathvec support misc debug sampling-asan rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))):$(gnulib-extralibdir) else # build-static @@ -1404,6 +1404,12 @@ else libsupport = $(common-objpfx)support/libsupport.a endif +ifeq ($(build-shared),yes) +libsamasan = $(common-objpfx)sampling-asan/libsamasan.so$(libsamasan.so-version) +else +libsamasan = $(common-objpfx)sampling-asan/libsamasan.a +endif + # This is a partial list of subdirectories containing the library source. # The order is more or less arbitrary. The sorting step will take care of the # dependencies and generate sorted-subdirs dynamically. @@ -1412,7 +1418,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ posix io termios resource misc socket sysvipc gmon \ gnulib iconv iconvdata wctype manual po argp \ localedata timezone rt conform debug mathvec support \ - dlfcn elf + dlfcn elf sampling-asan ifndef avoid-generated # sysd-sorted itself will contain rules making the sysd-sorted target diff --git a/shlib-versions b/shlib-versions index b1fd0a5eab..0d7b76c9d1 100644 --- a/shlib-versions +++ b/shlib-versions @@ -68,3 +68,7 @@ libmvec=1 # The malloc debug library libc_malloc_debug=0 + +# The sampling-asan library +libsamasan=0 + From patchwork Thu Nov 6 01:44:23 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123612 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9E263385DC07 for ; Thu, 6 Nov 2025 01:50:55 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9E263385DC07 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=ZsZdZ7+E X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) by sourceware.org (Postfix) with ESMTPS id 31B8C3854808 for ; Thu, 6 Nov 2025 01:44:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 31B8C3854808 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 31B8C3854808 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.33 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393497; cv=none; b=ARY9+LVE5IqDFlq05y2wLaJncZoTLy6rDTyX4mdHti26xpcbHMCmLx4BouTUJshJH5+penmhdV0ZM47GMj5ZaAzGlO9J2Asrdh5rfnqmG32HJ7pi24nj55XmU1R08HGKwWXBEPZLOWLQsNzgGeJschwJgSWqUB6khSS4bQRsBsU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393497; c=relaxed/simple; bh=3Wfg0VV47YJGnyYrFkYKRS0NGjpNPZG+MY+V/WhOhuA=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=xvUedz4D7C8wCoB+CR2CZrZaYJ/nxixflucWmkMD8SQ1Y1f/OK4K7MvoDyiljODC5I8lZ1ldNvqPl4JzOyiuPeUkBNPPPetpGsgEXLiS6gTc39UYfLMbMA37NyCj1alo39WKTOCsVVu1uklrLQiLwSDImkrli9fZsav61ylpOc0= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp032989d2a32747b663f46d60e2874823b7~1R4tHC3OT0432204322epoutp03P for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20251106014452epoutp032989d2a32747b663f46d60e2874823b7~1R4tHC3OT0432204322epoutp03P DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=aBOUm2ZGik9FizjQItjZhfMCAh9a+XNr4fr3jSmI1Eg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZsZdZ7+EbxGy0YL1zmvv7xNVytZXxUpL2ZHtHhcsI35tEOsCelWNTG0eFgg7Eipc9 u5xTrN8R2UtrFDtaX/Y1UizK1geoM8Ey7ti0g1zYx2YYjh556nqtq6vaFxC+u3W6st flCmqj71GzGmTX/KTQVygiPwC0Be1MvzzIwrervo= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p3bd675fff00ec273879d75bac66e40f38~1R4ss568l2804928049epcas1p38; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.99]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4d24kW6TPkz6B9m8; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p4ec8789cfcfbf4b977b2b5edc274d9dcb~1R4r0V2hR0033700337epcas1p4n; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip213b9aff9a7789b954e961cb798536c08~1R4rtNGuV2513225132epsmtip2I; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 6/9] sysdeps: Add libsamasan.abilist Date: Thu, 6 Nov 2025 10:44:23 +0900 Message-Id: <20251106014426.3767818-6-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p4ec8789cfcfbf4b977b2b5edc274d9dcb X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p4ec8789cfcfbf4b977b2b5edc274d9dcb References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Signed-off-by: Sung-hun Kim --- sysdeps/generic/libsamasan.abilist | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 sysdeps/generic/libsamasan.abilist diff --git a/sysdeps/generic/libsamasan.abilist b/sysdeps/generic/libsamasan.abilist new file mode 100644 index 0000000000..e69de29bb2 From patchwork Thu Nov 6 01:44:24 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123608 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9B974385DC02 for ; Thu, 6 Nov 2025 01:46:56 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout2.samsung.com (mailout2.samsung.com [203.254.224.25]) by sourceware.org (Postfix) with ESMTPS id 2E433385C6E0 for ; Thu, 6 Nov 2025 01:44:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2E433385C6E0 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2E433385C6E0 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.25 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; cv=none; b=A1ZEUvnc/SKS3tW34JYYfk/sWH/Z6+EaqXgeYdj+/7NBpxI/Y2X5I4AstUt8Pt07B/2rRVgnDe5e6/66LQ+BktR1USeoEqnkWLmvdGb1ISDOEb02bfIf2IDt0QtxzIL9lQRqTFntC1/rgkkPP4X9QvWj6z6ObIm8I4X8X+njEY0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393495; c=relaxed/simple; bh=crIf/oJwkqveFiWAcB8ogMUn7oVwzugchelPvo7yXe8=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=GY4meP2qMPL9szde6HBsa0W4mfFosMrytgRLL+VPQOkIM5Q5QIJWlcUhHueKrKDEwVAZxrhNo8++KxY98b4of3LQleR0g+i2+w+e4v4/wx+DG0wWRSUYBKWeEoV2PrriXivlrGluenEhlfkJ4sD5DIzsHCEDPVSUMIjjgnVF3kw= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp024513b5793278d370dabe4728de24afee~1R4tMl5lr1991319913epoutp02E for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20251106014452epoutp024513b5793278d370dabe4728de24afee~1R4tMl5lr1991319913epoutp02E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=MgAq+oToWEI5YlJAR1ela1kYrr6neX5IKv7iA4NhbQk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=isJn0mEmp1uRwqMrku7f5JKyI3yLRu2gXRjqpKm4h0UDeLZIaWuFEHVo8phxXHtFh qo+oAswHnNx6hzsyxu5H9/oubwRtc7zVRuSKL8+J+IM+aM/+fw6iYcXALarZ/+PKv8 dXnRGDW8w8mKo+Py+AGqlvdw/TpIQ4exgmelVT3A= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p38ad2b1ae708218eb98deb1d70ada4ccf~1R4s9aed63044330443epcas1p3J; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p1.samsung.com (unknown [182.195.38.98]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kW6nrjz3hhT4; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p1c7ebfd6aa870dffa7bd832f759830b12~1R4r6OmAr0845608456epcas1p1y; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip2968e20a2355246844099a59fb9d1ae88~1R4r07YnO2008820088epsmtip2Y; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 7/9] malloc, elf: Add malloc_sanitize to libc_malloc_debug.so Date: Thu, 6 Nov 2025 10:44:24 +0900 Message-Id: <20251106014426.3767818-7-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p1c7ebfd6aa870dffa7bd832f759830b12 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p1c7ebfd6aa870dffa7bd832f759830b12 References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org A new hook, malloc_sanitize, has been introduced to provide address sanitization extension for glibc malloc. As a proof of concept, I have implemented sampling-asan as the back-end method of malloc_sanitize. This feature can be enabled by setting the MALLOC_SANITIZE_ tunable as follows: $ LD_PRELOAD=/path/to/libc_malloc_debug.so MALLOC_SANITIZE_=sampling-asan fore configuring runtime options of sampling-asan, please refer the README in the sampling-asan directory. To pass tst-rtld-list-tunables in elf, the new tunable is added in the tst-rtld-list-unables.exp file. Signed-off-by: Sung-hun Kim --- Rules | 20 +++++ elf/dl-tunables.list | 6 ++ elf/tst-rtld-list-tunables.exp | 1 + malloc/Depend | 1 + malloc/Makefile | 13 +++ malloc/malloc-debug.c | 18 ++++ malloc/malloc-sanitize.c | 147 +++++++++++++++++++++++++++++++++ malloc/tst-malloc-sanitize.c | 78 +++++++++++++++++ 8 files changed, 284 insertions(+) create mode 100644 malloc/malloc-sanitize.c create mode 100644 malloc/tst-malloc-sanitize.c diff --git a/Rules b/Rules index dd319e8013..d623fc2b9a 100644 --- a/Rules +++ b/Rules @@ -167,6 +167,7 @@ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \ $(tests-malloc-hugetlb1:%=$(objpfx)%-malloc-hugetlb1.out) \ $(tests-malloc-hugetlb2:%=$(objpfx)%-malloc-hugetlb2.out) \ $(tests-malloc-largetcache:%=$(objpfx)%-malloc-largetcache.out) \ + $(tests-malloc-sanitize:%=$(objpfx)%-malloc-sanitize.out) \ $(tests-special) $(tests-printers-out) xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special) endif # $(run-built-tests) != no @@ -182,6 +183,7 @@ tests-expected = $(tests) $(tests-internal) $(tests-printers) \ $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \ $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) \ $(tests-malloc-largetcache:%=%-malloc-largetcache) \ + $(tests-malloc-sanitize:%=%-malloc-sanitize) \ $(tests-mcheck:%=%-mcheck) xtests-expected = $(xtests) endif # $(run-built-tests) != no @@ -223,6 +225,7 @@ binaries-malloc-check-tests = $(tests-malloc-check:%=%-malloc-check) binaries-malloc-hugetlb1-tests = $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) binaries-malloc-hugetlb2-tests = $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) binaries-malloc-largetcache-tests = $(tests-malloc-largetcache:%=%-malloc-largetcache) +binaries-malloc-sanitize-tests = $(tests-malloc-sanitize:%=%-malloc-sanitize) else binaries-all-notests = binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs) @@ -237,6 +240,7 @@ binaries-malloc-check-tests = binaries-malloc-hugetlb1-tests = binaries-malloc-hugetlb2-tests = binaries-malloc-largetcache-tests = +binaries-malloc-sanitize-tests = endif binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests) @@ -311,6 +315,14 @@ $(addprefix $(objpfx),$(binaries-malloc-largetcache-tests)): %-malloc-largetcach $(+link-tests) endif +ifneq "$(strip $(binaries-malloc-sanitize-tests))" "" +$(addprefix $(objpfx),$(binaries-malloc-sanitize-tests)): %-malloc-sanitize: %.o \ + $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-tests) +endif + ifneq "$(strip $(binaries-pie-tests))" "" $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ $(link-extra-libs-tests) \ @@ -366,6 +378,14 @@ $(1)-malloc-largetcache-ENV += GLIBC_TUNABLES=glibc.malloc.tcache_max=1048576 endef $(foreach t,$(tests-malloc-largetcache),$(eval $(call malloc-largetcache-ENVS,$(t)))) +# All malloc-sanitize tests will be run with MALLOC_SANITIZE_=sampling-asan +define malloc-sanitize-ENVS +$(1)-malloc-sanitize-ENV = MALLOC_SANITIZE_=sampling-asan SAMASAN_ENABLE=true \ + SAMASAN_SAMPLING_RATE=1.0 SAMASAN_MAX_ALLOC_SIZE=4096 \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so +endef +$(foreach t,$(tests-malloc-sanitize),$(eval $(call malloc-sanitize-ENVS,$(t)))) + # mcheck tests need the debug DSO to support -lmcheck. define mcheck-ENVS $(1)-mcheck-ENV = LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list index c03c9967f0..dd4804b77b 100644 --- a/elf/dl-tunables.list +++ b/elf/dl-tunables.list @@ -82,6 +82,12 @@ glibc { type: SIZE_T minval: 0 } + malloc_sanitize { + type: STRING + minval: 7 + maxval: 13 + env_alias: MALLOC_SANITIZE_ + } } elision { diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp index 8df6f5906e..b948d4a503 100644 --- a/elf/tst-rtld-list-tunables.exp +++ b/elf/tst-rtld-list-tunables.exp @@ -2,6 +2,7 @@ glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0x[f]+) glibc.malloc.arena_test: 0x0 (min: 0x1, max: 0x[f]+) glibc.malloc.check: 0 (min: 0, max: 3) glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0x[f]+) +glibc.malloc.malloc_sanitize: glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647) glibc.malloc.mmap_threshold: 0x0 (min: 0x0, max: 0x[f]+) glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+) diff --git a/malloc/Depend b/malloc/Depend index ed18c37b80..0fdf7b2923 100644 --- a/malloc/Depend +++ b/malloc/Depend @@ -2,3 +2,4 @@ dlfcn nptl htl rt +sampling-asan diff --git a/malloc/Makefile b/malloc/Makefile index cc012e2921..9756ad3564 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -41,6 +41,7 @@ tests := \ tst-malloc-check \ tst-malloc-fork-deadlock \ tst-malloc-random \ + tst-malloc-sanitize \ tst-malloc-stats-cancellation \ tst-malloc-tcache-leak \ tst-malloc-thread-exit \ @@ -106,6 +107,7 @@ tests-exclude-malloc-check = \ tst-compathooks-off \ tst-compathooks-on \ tst-malloc-check \ + tst-malloc-sanitize \ tst-malloc-tcache-leak \ tst-malloc-usable \ tst-mallocfork2 \ @@ -131,6 +133,7 @@ tests-exclude-hugetlb1 = \ tst-interpose-static-nothread \ tst-interpose-static-thread \ tst-interpose-thread \ + tst-malloc-sanitize \ tst-malloc-tcache-leak \ tst-malloc-usable \ tst-malloc-usable-tunables \ @@ -157,6 +160,7 @@ tests-exclude-largetcache = \ tst-interpose-static-thread \ tst-interpose-thread \ tst-malloc-backtrace \ + tst-malloc-sanitize \ tst-malloc-usable \ tst-malloc-usable-tunables \ tst-mallocstate \ @@ -177,6 +181,7 @@ tests-exclude-mcheck = \ tst-compathooks-on \ tst-malloc-backtrace \ tst-malloc-fork-deadlock \ + tst-malloc-sanitize \ tst-malloc-stats-cancellation \ tst-malloc-tcache-leak \ tst-malloc-thread-exit \ @@ -384,6 +389,9 @@ tst-malloc-usable-ENV = MALLOC_CHECK_=3 \ LD_PRELOAD=$(objpfx)/libc_malloc_debug.so tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \ LD_PRELOAD=$(objpfx)/libc_malloc_debug.so +tst-malloc-sanitize-ENV = MALLOC_SANITIZE_=sampling-asan SAMASAN_ENABLE=true \ + SAMASAN_SAMPLING_RATE=1.0 SAMASAN_MAX_ALLOC_SIZE=4096 \ + LD_PRELOAD=$(objpfx)/libc_malloc_debug.so tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0 @@ -394,6 +402,11 @@ CPPFLAGS-malloc.c += -DUSE_TCACHE=1 CFLAGS-tst-tcfree3.c += -fno-builtin-malloc -fno-builtin-free +LDFLAGS-tst-malloc-sanitize += -lsamasan +LDFLAGS-tst-malloc-sanitize += -L$(common-objpfx)sampling-asan -Wl,-rpath-link=$(objpfx)../sampling-asan + +$(objpfx)libc_malloc_debug.so: $(common-objpfx)sampling-asan/libsamasan.so$(libsamasan.so-version) + sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,') $(objpfx)mtrace: mtrace.pl diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c index 15867e23c5..35169469aa 100644 --- a/malloc/malloc-debug.c +++ b/malloc/malloc-debug.c @@ -52,6 +52,8 @@ enum malloc_debug_hooks MALLOC_MCHECK_HOOK = 1 << 0, /* mcheck() */ MALLOC_MTRACE_HOOK = 1 << 1, /* mtrace() */ MALLOC_CHECK_HOOK = 1 << 2, /* MALLOC_CHECK_ or glibc.malloc.check. */ + MALLOC_SANITIZE_HOOK = 1 << 3, /* MALLOC_SANITIZE_ or + glibc.malloc.sanitize. */ }; static unsigned __malloc_debugging_hooks; @@ -76,6 +78,7 @@ __malloc_debug_disable (enum malloc_debug_hooks flag) #include "mcheck.c" #include "mtrace.c" #include "malloc-check.c" +#include "malloc-sanitize.c" #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_24) extern void (*__malloc_initialize_hook) (void); @@ -118,6 +121,8 @@ generic_hook_ini (void) will not try to optimize it away. */ __libc_free (__libc_malloc (0)); + initialize_malloc_sanitize (); + #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_24) void (*hook) (void) = __malloc_initialize_hook; if (hook != NULL) @@ -158,6 +163,8 @@ __debug_malloc (size_t bytes) void *(*hook) (size_t, const void *) = __malloc_hook; if (__glibc_unlikely (hook != NULL)) return (*hook)(bytes, RETURN_ADDRESS (0)); + if (__is_malloc_debug_enabled (MALLOC_SANITIZE_HOOK)) + return malloc_sanitize (bytes); void *victim = NULL; size_t orig_bytes = bytes; @@ -185,6 +192,11 @@ __debug_free (void *mem) (*hook)(mem, RETURN_ADDRESS (0)); return; } + if (__is_malloc_debug_enabled (MALLOC_SANITIZE_HOOK)) + { + free_sanitize (mem); + return; + } if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)) mem = free_mcheck (mem); @@ -205,6 +217,9 @@ __debug_realloc (void *oldmem, size_t bytes) if (__glibc_unlikely (hook != NULL)) return (*hook)(oldmem, bytes, RETURN_ADDRESS (0)); + if (__is_malloc_debug_enabled (MALLOC_SANITIZE_HOOK)) + return realloc_sanitize (oldmem, bytes); + size_t orig_bytes = bytes, oldsize = 0; void *victim = NULL; @@ -322,6 +337,9 @@ __debug_calloc (size_t nmemb, size_t size) { size_t bytes; + if (__is_malloc_debug_enabled (MALLOC_SANITIZE_HOOK)) + return calloc_sanitize (nmemb, size); + if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes))) { errno = ENOMEM; diff --git a/malloc/malloc-sanitize.c b/malloc/malloc-sanitize.c new file mode 100644 index 0000000000..a26fb1d60f --- /dev/null +++ b/malloc/malloc-sanitize.c @@ -0,0 +1,147 @@ +/* glibc.malloc.sanitize implementation. + Copyright (C) 2024-2025 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; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include // for realloc_sanitize () +#include // for realloc_sanitize () + +static void * +malloc_sanitize (size_t bytes) +{ + void *ptr = NULL; + + if (samasan_sampling_ok (bytes)) + ptr = samasan_allocate (bytes); + // Even if samasan_allocate is failed, fall back to the normal + // malloc path to guarantee memory allocation. + if (__glibc_unlikely (!ptr)) + ptr = __libc_malloc (bytes); + return ptr; +} + +static void +free_sanitize (void *mem) +{ + if (samasan_is_pointer_in_sampling_pool (mem)) + samasan_free (mem); + else + __libc_free (mem); +} + +static void * +realloc_sanitize (void *oldmem, size_t bytes) +{ + void *mem; + if (oldmem == 0) + return malloc_sanitize (bytes); + if (samasan_sampling_ok (bytes)) + { + mem = samasan_allocate (bytes); + if (mem != 0) + { + size_t oldsize; + memset (mem, 0, bytes); + if (samasan_is_pointer_in_sampling_pool (oldmem)) + oldsize = samasan_get_size (oldmem); + else + oldsize = memsize (mem2chunk (oldmem)); + if (oldsize > bytes) + memcpy (mem, oldmem, bytes); + else + memcpy (mem, oldmem, oldsize); + free_sanitize (oldmem); + return mem; + } + } + if (!samasan_is_pointer_in_sampling_pool (oldmem)) + return __libc_realloc (oldmem, bytes); + + /* Oldmem points a sampled memory block. Let's mimic __libc_realloc */ + mem = __libc_malloc (bytes); + if (mem != 0) + { + size_t oldsize = samasan_get_size (oldmem); + if (oldsize > bytes) + memcpy (mem, oldmem, bytes); + else + memcpy (mem, oldmem, oldsize); + samasan_free (oldmem); + } + return mem; +} + +static void * +calloc_sanitize (size_t num, size_t bytes) +{ + void *mem; + size_t size; + + if (__glibc_unlikely (__builtin_mul_overflow (num, bytes, &size))) + { + __set_errno (ENOMEM); + return NULL; + } + + if (samasan_sampling_ok (size)) + { + mem = samasan_allocate (size); + if (mem != 0) + { + memset (mem, 0, size); + return mem; + } + } + /* Fall through */ + return __libc_calloc (num, bytes); +} + +#define SAMPLING_ASAN_FULL_LEN 13 +#define SAMPLING_ASAN_FULL_NAME "sampling-asan" +#define SAMPLING_ASAN_SHORT_LEN 7 +#define SAMPLING_ASAN_SHORT_NAME "samasan" + +static inline bool is_tunable_sampling_asan (const char *str, size_t len) +{ + if (len == 0) + return false; + if (len == SAMPLING_ASAN_FULL_LEN && + !strncmp (str, SAMPLING_ASAN_FULL_NAME, len)) + return true; + if (len == SAMPLING_ASAN_SHORT_LEN && + !strncmp (str, SAMPLING_ASAN_SHORT_NAME, len)) + return true; + return false; +} + +static void +TUNABLE_CALLBACK (set_malloc_sanitize) (tunable_val_t *valp) +{ + const char *value = (char *) valp->strval.str; + size_t len = valp->strval.len; + if (is_tunable_sampling_asan (value, len)) + __malloc_debug_enable (MALLOC_SANITIZE_HOOK); +} + +static bool +initialize_malloc_sanitize (void) +{ + samasan_init (); + TUNABLE_GET (malloc_sanitize, const struct tunable_str_t *, TUNABLE_CALLBACK (set_malloc_sanitize)); + return __is_malloc_debug_enabled (MALLOC_SANITIZE_HOOK); +} diff --git a/malloc/tst-malloc-sanitize.c b/malloc/tst-malloc-sanitize.c new file mode 100644 index 0000000000..71f619c7fa --- /dev/null +++ b/malloc/tst-malloc-sanitize.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2024-2025 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sampling-asan/samasan_init.h" /* for samasan_deinit () */ + +static int +do_test (void) +{ + void *ptr; + const size_t alloc_size = 512; + char *c; + int i, ok; + + errno = 0; + + ptr = malloc (alloc_size); + TEST_VERIFY (samasan_is_pointer_in_sampling_pool (ptr)); + free (ptr); + + /* Since a memory_block size is 4096, an allocation request for + 512 * 10 bytes should be falled back to __libc_malloc. */ + ptr = malloc (alloc_size * 10); + TEST_VERIFY (!samasan_is_pointer_in_sampling_pool (ptr)); + free (ptr); + + ptr = realloc (NULL, alloc_size); + TEST_VERIFY (samasan_is_pointer_in_sampling_pool (ptr)); + ptr = realloc (ptr, alloc_size * 2); + TEST_VERIFY (samasan_is_pointer_in_sampling_pool (ptr)); + ptr = realloc (ptr, alloc_size * 10); + /* Allocation size crosses the limitation of sampling-asan. + It should be allocated by the normal malloc path. */ + TEST_VERIFY (!samasan_is_pointer_in_sampling_pool (ptr)); + free (ptr); + + ptr = calloc (1, alloc_size); + TEST_VERIFY (samasan_is_pointer_in_sampling_pool (ptr)); + c = (char *) ptr; + ok = 0; + for (i = 0; i < alloc_size; i++) + if (c[i] == 0) + ok++; + TEST_VERIFY (ok == alloc_size); + free (ptr); + + /* Since a memory_block size is 4096, an allocation request for + 512 * 10 bytes should be falled back to __libc_calloc. */ + ptr = calloc (10, alloc_size); + TEST_VERIFY (!samasan_is_pointer_in_sampling_pool (ptr)); + + return 0; +} + +#include From patchwork Thu Nov 6 01:44:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123609 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9D7C1385DC09 for ; Thu, 6 Nov 2025 01:46:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9D7C1385DC09 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=ZFt1ELem X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) by sourceware.org (Postfix) with ESMTPS id 2ED3F3854804 for ; Thu, 6 Nov 2025 01:44:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2ED3F3854804 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2ED3F3854804 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.34 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393496; cv=none; b=VFRii/y/drQrzByg0opwNCYFn5MKsnWzHRYaHvdsI9dWck1VULoHEd3aYF5cRDRe8wGvtk28bQuYyOXXw2bA56Q+LzG+7e8MRT4Pn27UmhP+r/XgW8p8jHLN67HCwLL7WhMhlgG0JSowhGng2vVXGxpAily5+gFO6urPaa5JEj4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393496; c=relaxed/simple; bh=J0xFEjeso2SFNfHZGrxVjMhfWa2ugZNHnUyvJ2O7v3g=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=xvtiu3gNwc4z+i2p0xpxNp4aC/ogK1Q+pA+gYlBphTGMlAtsUE571D9Tyujnn5TrcjniSXa5eF1foei1mXtXJ5eYjRjoWjepZzYl67zd0HvWHzy+Zzs6P36DqgKDUhjl83WAkNPegf37gAR4y/vEXJPehw//PMoFAB0INQt4gJk= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20251106014452epoutp04c41904b9af31399fb6beb861503a6e62~1R4tR145S0054800548epoutp04u for ; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20251106014452epoutp04c41904b9af31399fb6beb861503a6e62~1R4tR145S0054800548epoutp04u DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393492; bh=quqpwOtsRj8F9dpGS6SvyH9DgxRutvIpRFF+X/P/kNQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZFt1ELem2qjYjdCf3N0jIBxy6Oajhpu+DR/CfNmFiaieCOs3kEc1tco9eatAYkF1/ UIyDkbw4KPLN5nCU1ADUe2xjI5FS2R7T3mRS/E0HAhiGNmDVMIb4k7Ub0FfxMx6bas Iov8/In6b0eEddxvWOS3Ur6q27iJxhK5jedHWhLE= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p127beedf60251a52f58b6107c7fc58882~1R4tBSj2t0845608456epcas1p16; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p2.samsung.com (unknown [182.195.38.109]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kX02n5z3hhT7; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p1af3a4b35e68b22d84a4c7d7c8ddc9051~1R4r-u18D1327413274epcas1p1q; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip2d4f0bd425ace63bb5281c3363b633d2d~1R4r6yvg12513225132epsmtip2J; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 8/9] manual: Add descriptions for sampling-asan in the manual Date: Thu, 6 Nov 2025 10:44:25 +0900 Message-Id: <20251106014426.3767818-8-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p1af3a4b35e68b22d84a4c7d7c8ddc9051 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p1af3a4b35e68b22d84a4c7d7c8ddc9051 References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org This patch includes following changes: * A new section "Memory Debugging" is added as a part of Chapter 3 "Virtual Memory Allocation And Paging". * A description for a newly added tunable "libc.malloc.malloc_sanitize" is added. The new section can be extended to include other memory debugging features. But for now, brief description of address sanitization and full description of sampling-asan are added. Signed-off-by: Sung-hun Kim --- manual/memory.texi | 144 +++++++++++++++++++++++++++++++++++++++++++ manual/tunables.texi | 13 ++++ 2 files changed, 157 insertions(+) diff --git a/manual/memory.texi b/manual/memory.texi index dd6c7f9996..3b3a311687 100644 --- a/manual/memory.texi +++ b/manual/memory.texi @@ -19,6 +19,7 @@ and allocation of real memory. * Resizing the Data Segment:: @code{brk}, @code{sbrk} * Memory Protection:: Controlling access to memory regions. * Locking Pages:: Preventing page faults +* Memory Debugging:: Debugging wrong memory allocation/free/accesses. @end menu Memory mapped I/O is not discussed in this chapter. @xref{Memory-mapped I/O}. @@ -3687,8 +3688,151 @@ calls can fail, so there are no specific @code{errno} values. @end deftypefun +@node Memory Debugging +@section Memory Debugging + +You can meet memory-related bugs, such as dangling pointers, whenever +you write the code. +This is because the nature of the C launguage enforces the +responsibility of managing the lifecycle of allocated memory objects +to authors. + +@node Address Sanitization Overview +@subsection Address Sanitization Overview + +AddressSanitizer +(@pxref{Instrumentation Options,, Program Instrumentation Options, gcc, Using GCC}) +is commonly used to detect a subset (but most of) of memory bugs at +the expense of runtime overhead. +AddressSanitizer instruments memory access code and hooks memory +allocation and deallocation to track memory states. +Memory states are stored in a separate metadata area known as shadow +memory. +AddressSanitizer uses shadow memory for detecting memory bugs, such as +accessing a freed memory object. + + +@node Sampling-based Address Sanitization +@subsection Sampling-based Address Sanitization + +While AddressSanitizer provides a comprehensive method to detect memory +bugs, its impact on performance makes developers to hesitate using +it for bug detection. +Sampling-asan offers an alternative way to this case by significanlty +reducing runtime overhead through a sampling-based approach. +Sampling-asan randomly selects memory allocations for sanitization. +For each allocation, it "tosses a coin" to decide whether to sample it. +If the allocation is selected for sampling, sampling-asan forwards it +to the internal memory allocator. +The internal memory allocator in sampling-asan uses a preallocated +memory pool and a metadata area. +The state of each entry in the preallocated memory pool and the call +stacks of allocation/deallocation of the memory object are recorded in +the metadata area. + +Sampling-asan leverages the OS kernel's memory protection mechanism, +particularly the segmentation violation signal (@code{SIGSEGV}), to +detect memory bugs. +When a @code{SIGSEGV} is raised, the registered signal handler +diagnoses the kind of the memory bug. +Then, it emits a bug report and determines to keep the application +running or not depending on the configuration. + +Note that, unlike AdderssSanitizer, sampling-asan can detect memory bugs +on heap only. + + +@node How to Use Sampling-asan +@subsection How to Use Sampling-asan + +Currently, sampling-asan is served as an independent shared library +(@code{libsamasan.so}) which is running a backend for +@code{libc_malloc_debug.so}. +Thus, if you want use sampling-asan, the program should be compiled +with @code{-lsamasan}. +The @code{glibc.malloc.malloc_sanitize} tunable determines which backend +is used to @code{malloc} sanitization. +For now, only sampling-asan can be used for this purpose (use +@code{MALLOC_SANITIZE_} as an alias of +@code{glibc.malloc_malloc_sanitize}.). + +Sampling-asan provides configurable options via environment variables. +Below is a list of configurable options and their descriptions +(note that every configurable options have SAMASAN_ as a prefix): + +@table @code +@item SAMASAN_ENABLE +Enable sampling-asan. +You can use "true", "yes", "enable", and "on" to activate it; +other values disable it (default: false). + +@item SAMASAN_MAX_ALLOC_SIZE +Set the upper limit of the sanitized allocation size in bytes +(default: 4096). +Allocations larger than this limits fall back to the normal +@code{malloc} call. + +@item SAMASAN_MAX_ON_GOING_ALLOCATIONS +Set the maximum number of concurrent sanitized allocations +(default: 100). +Once this limit is reached, further allocations are not sanitized. +They fall back to the normal @code{malloc} call. +The size of the preallocated memory pool is decided by this value +and the SAMASAN_PARTITION_SIZE setting. + +@item SAMASAN_SAMPLING_RATE +Set the sampling rate (default: 0.005). +You should use a floating point number between 0 to 1.0. +For example, if a sampling rate is 0.005, five calls out of every +thousand calls are sampled statistically. + +@item SAMASAN_OUTPUT_PATH +Set the output path for a bug report (default: @code{stderr}). +You should use an absolute path like "/tmp/bug-report". + +@item SAMASAN_PARTITION_SIZE +Set the size of a partition in bytes (default: 4096). +A partition is a protected memory area and does not allow any access +on it. +Two partitions enclose a memory block in the preallocated memory pool. +The total number of partitions is calculated as +SAMASAN_MAX_ON_GOING_ALLOCATIONS + 1. +If zero is given, partitions are not allocated. + +@item SAMASAN_PAUSE_ON_FORK +Decide to pause sampling-asan when a new process is forked or not. +You can use "true", "yes", "enable", and "on" (default is "true"). +Other values disable this configuration. + +@item SAMASAN_CHUNK_PICK +Specify a chunk area with in a memory block to be used. +You can use "LEFT", "CENTER", and "RIGHT" (default: "CENTER"). +If you specify "LEFT", sampling-asan allocates a memory chunk +at the leftmost in the selected memory block. +Other values will cause sampling-asan initialization to fail. + +@item SAMASAN_CONTINUE_ON_CRASH +Determine whether the application continues running after detecting +a memory bug (default: false). +In production environments, developers may prefer to keep the +application running even after detecting a memory bug. +If you set this value to true, sampling-asan does not terminate the +application if the detected bug is recoverable. + +@end table + +Here is a simple example of how to use sampling-asan. +@smallexample + $ export SAMASAN_ENABLE=true + $ export SAMASAN_MAX_ON_GOING_ALLOCATIONS=100 + $ export SAMASAN_OUTPUT_PATH=/tmp/bug-report + $ LD_PRELOAD=/usr/lib/libc_malloc_debug.so MALLOC_SANITIZE_=sampling-asan + +@end smallexample +You can find the bug report at @code{/tmp/bug-report} when a memory +bug is occurred. @ignore @c This was never actually implemented. -zw diff --git a/manual/tunables.texi b/manual/tunables.texi index e4592e23cc..aaa7d9601e 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -45,6 +45,7 @@ glibc.mem.tagging: 0 (min: 0, max: 255) glibc.elision.tries: 3 (min: 0, max: 2147483647) glibc.elision.enable: 0 (min: 0, max: 1) glibc.malloc.hugetlb: 0x0 (min: 0x0, max: 0xffffffffffffffff) +glibc.malloc.malloc_sanitize: glibc.cpu.x86_rep_movsb_threshold: 0x2000 (min: 0x100, max: 0xffffffffffffffff) glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0xffffffffffffffff) glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) @@ -294,6 +295,18 @@ supported ones. If provided value is invalid, @code{MAP_HUGETLB} will not be used. @end deftp +@deftp Tunable glibc.malloc.malloc_sanitize +This tunable configures the backend used for sanitizing @code{malloc}. +It requires a string specified with @code{=} (e.g., +@code{glibc.malloc.malloc_sanitize=sampling-asan}). +Currently, sampling-asan is only available as a sanitization backend. +You can use @code{MALLOC_SANITIZE_} as an alias of this tunable. + +Sanitization refers to various methods used to verify whether a function +has executed correctly or not. In this context, we focus solely on address +sanitization as the sanitization method to keep clarity and simplicity. +@end deftp + @node Dynamic Linking Tunables @section Dynamic Linking Tunables @cindex dynamic linking tunables From patchwork Thu Nov 6 01:44:26 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sung-hun Kim X-Patchwork-Id: 123607 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CC7AF385DC06 for ; Thu, 6 Nov 2025 01:46:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CC7AF385DC06 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=samsung.com header.i=@samsung.com header.a=rsa-sha256 header.s=mail20170921 header.b=TBArSGTW X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) by sourceware.org (Postfix) with ESMTPS id 2C0EE385C6FC for ; Thu, 6 Nov 2025 01:44:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2C0EE385C6FC Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=samsung.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2C0EE385C6FC Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=203.254.224.24 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393496; cv=none; b=nhJVixBN2956Adut+wgETWlUCg4VsDJUQPghl4CeSkYtqvmwUu/dsmndXQFIZiCBGidbPAsjAZmXhH+gsEhDBbq+7N9gYdJk1IAaIx19zGbuwocPjU4f25Uf4gAWSyFVUR2LqOk9PZYcZNKh11vQkiGnCmpiBkiJb3V/wfRY4vI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1762393496; c=relaxed/simple; bh=b0Xo7EcMd3031CFLpaC/jPNV5hWUL2TEphyL/2mED2Q=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=Y339COnT2kD1AWinkD4vOOH6qdehz0hvScKxMETglBCanUCPyDlXw/JqIQC+HLmQwc/Uc5/NjFlzvxluo6fvpfBdv7jJDDknkH2dVGnAxJO4Gb0rnxLbJgEl5zpwbcafP57qnXj3H0z2Y5yd1pdBUbWo4F4QoKPs6JyB9u9Yirc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2C0EE385C6FC Received: from epcas1p1.samsung.com (unknown [182.195.41.45]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20251106014453epoutp01c073e7b92e932af354cf110a8edd543e~1R4taJJm02702527025epoutp01k for ; Thu, 6 Nov 2025 01:44:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20251106014453epoutp01c073e7b92e932af354cf110a8edd543e~1R4taJJm02702527025epoutp01k DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1762393493; bh=sFPLkP+n/0eYEIgZN24VBjoTQtuy/QY2v340kU/uhns=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TBArSGTWis/YfuC/k6jfz6E8Vr3hf7pHkxNi/pltGxMGwVah7Cltbxy/F0LJUP/FU 2I3kewhV4X6dUI8RJqqiKoaLNuqw4YD5NgwX94+hGjbaGnzEysWcFt35lZwVkcBAfN DrP72Xtkdrz9tUGkeIg5/l1RwNb6fFAD+0v4YCK8= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPS id 20251106014452epcas1p4f8c995aa555e9904e6ff9b441b10c2a3~1R4tIIUNh2995829958epcas1p4s; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epcas1p2.samsung.com (unknown [182.195.38.98]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4d24kX10Fbz3hhTB; Thu, 6 Nov 2025 01:44:52 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epcas1p44dcd7782392de44546f9d4c4d0b8a937~1R4sHeahS2995829958epcas1p4m; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20251106014451epsmtip28838076bf1a52924ab87c78fd86d72eb~1R4sAQXpZ2008820088epsmtip2Z; Thu, 6 Nov 2025 01:44:51 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: adhemerval.zanella@linaro.org, josmyers@redhat.com, fweimer@redhat.com, carlos@systemhalted.org, sebuns@gmail.com, dongkyun.s@samsung.com, sungguk.na@samsung.com, sfoon.kim@samsung.com Subject: [PATCH v4 9/9] NEWS: Add a new feature sampling-asan Date: Thu, 6 Nov 2025 10:44:26 +0900 Message-Id: <20251106014426.3767818-9-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20251106014426.3767818-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20251106014451epcas1p44dcd7782392de44546f9d4c4d0b8a937 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20251106014451epcas1p44dcd7782392de44546f9d4c4d0b8a937 References: <20251106014426.3767818-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org Signed-off-by: Sung-hun Kim --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 6ffc7df286..210172d11b 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,13 @@ Major new features: arguments to support expressions with a comma inside a compound literal initializer not surrounded by parentheses. +* A new memory debugging feature, sampling-asan, has been added. + Sampling-asan provides a sampling-based address sanitization. + [m|r|c]alloc_sanitize and free_sanitize calls are added in malloc-debug.c + and they forward [m|r|c]alloc and free calls to sampling-asan. To use + sampling-asan, pass "MALLOC_SANITIZE_=sampling-asan" as an environment + variable. + Deprecated and removed features, and other changes affecting compatibility: * Support for dumped heaps has been removed - malloc_set_state() now always