From patchwork Thu Sep 25 08:55:59 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: 120834 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 ED964385840C for ; Thu, 25 Sep 2025 09:08:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ED964385840C 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=KHvL8zJm 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 1679B3858405 for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1679B3858405 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 1679B3858405 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=1758790609; cv=none; b=S4n3ZqFFKYb/QsD5ZRFQhwwA0NcPKESZ6HGg9ikqb6sgbYynDB3YQK3NcbxrzI9OHvMq7bCZ9miwlUHsEA42E7FL22xwrH+Xj8FC/6l/mffnYv1q3QbwsKvZ4XZ9xZ2z+7QBhg3o9JAeSj0s4Mn8qH3lK0kTzjO/KF/y3V7AhOg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=omEIkvE27oD1agnB7YvgECCZuH4YGRkhHVog2Y+u/GE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=WguxWHIRaW+XJp8rNKV+6lpZdDwm+/kNXDAfUp2dkdZvsRcQ1bnUbruF80hVN51tNgwZV8UdiIFkN/J8pUCj9Q1/pCG/mm5+VnKicgcauIOpsmYkKSHOzKFGt0C2RzJy+Ayn2L4zYfrCsQMOu7NM9NExGoVm2E4Asg+HKDwy+ZU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1679B3858405 Received: from epcas1p2.samsung.com (unknown [182.195.41.46]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp0424640dce8bfe626cdf5600499a73d845~oerzOGgwg1893118931epoutp04f for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250925085645epoutp0424640dce8bfe626cdf5600499a73d845~oerzOGgwg1893118931epoutp04f DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=fvzqI8HSHBKR9pT+HCqry0h6EsB7lXkewS5kIxtZZ+8=; h=From:To:Cc:Subject:Date:References:From; b=KHvL8zJmdx4VRn4u7oziB/9MV970Ps/oLvE3oMij+M4mCBd//MCeZc6zGjUkiouN0 2sW8TXQZsnM7k6miuvpk8hoXAQGM67cP5RGVBm5tzXUgIHcTQTyDtDxybqC3kxi3wt kswGovJR76yamfOCNuYJCAwwuZNJXBuHxX1CnflA= Received: from epsnrtp02.localdomain (unknown [182.195.42.154]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p32900bf4dd06695797d0c39316ff6c253~oeryp-OYd0442104421epcas1p3J; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.104]) by epsnrtp02.localdomain (Postfix) with ESMTP id 4cXSJD2zKsz2SSKg; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20250925085643epcas1p4c571194fff4f52de403bf6d0d3e114e7~oerxcSg8V1466414664epcas1p4b; Thu, 25 Sep 2025 08:56:43 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085643epsmtip106c62dbb018aad6c054c87641e021bea~oerxWK6cu0321803218epsmtip1u; Thu, 25 Sep 2025 08:56:43 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 1/9] sampling-asan: A sampling-based address sanitization for on-line memory bug detection Date: Thu, 25 Sep 2025 17:55:59 +0900 Message-Id: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-CMS-MailID: 20250925085643epcas1p4c571194fff4f52de403bf6d0d3e114e7 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085643epcas1p4c571194fff4f52de403bf6d0d3e114e7 References: X-Spam-Status: No, score=-12.3 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_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 [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 | 23 + sampling-asan/Makefile | 29 ++ sampling-asan/Versions | 17 + sampling-asan/samasan.h | 44 ++ sampling-asan/samasan_allocate.c | 648 ++++++++++++++++++++++++ sampling-asan/samasan_allocate.h | 69 +++ sampling-asan/samasan_backtrace.c | 58 +++ sampling-asan/samasan_backtrace.h | 30 ++ sampling-asan/samasan_common.c | 25 + sampling-asan/samasan_common.h | 100 ++++ sampling-asan/samasan_error.c | 117 +++++ sampling-asan/samasan_error.h | 48 ++ sampling-asan/samasan_fault_handler.c | 125 +++++ sampling-asan/samasan_fault_handler.h | 24 + sampling-asan/samasan_init.c | 353 +++++++++++++ sampling-asan/samasan_init.h | 34 ++ sampling-asan/samasan_report.c | 244 +++++++++ sampling-asan/samasan_report.h | 35 ++ sampling-asan/samasan_sampling.c | 67 +++ sampling-asan/samasan_sampling.h | 28 + sampling-asan/samasan_variable_init.def | 37 ++ 21 files changed, 2155 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..cf8a445950 --- /dev/null +++ b/include/samasan.h @@ -0,0 +1,23 @@ +/* Sampling-asan for debugging memory allocation. + Copyright (C) 2015-2024 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 + +/* _SAMASAN_H will be defined in the below header. */ +#include + +#endif /* samasan.h */ diff --git a/sampling-asan/Makefile b/sampling-asan/Makefile new file mode 100644 index 0000000000..70f639dab5 --- /dev/null +++ b/sampling-asan/Makefile @@ -0,0 +1,29 @@ +# 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 +# . + +# Makefile for sampling-asan routines + +subdir := sampling-asan + +include ../Makeconfig + +dist-headers := samasan.h +headers := $(dist-headers) +routines := samasan_allocate samasan_error samasan_sampling samasan_common \ + samasan_init samasan_report samasan_backtrace samasan_fault_handler + +include ../Rules diff --git a/sampling-asan/Versions b/sampling-asan/Versions new file mode 100644 index 0000000000..0d7499558c --- /dev/null +++ b/sampling-asan/Versions @@ -0,0 +1,17 @@ +libc { + 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..f5d8443dfa --- /dev/null +++ b/sampling-asan/samasan.h @@ -0,0 +1,44 @@ +/* Prototypes for the sampling-asan interfaces. + 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 + . */ + +#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..c021523e56 --- /dev/null +++ b/sampling-asan/samasan_allocate.c @@ -0,0 +1,648 @@ +/* Definitions for the sanitized memory allocation 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; 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 /* for mmap/munmap */ +#include /* for __dso_handle */ +#include /* for __register_atfork */ + +#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 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; +} + +/* 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 (!fork_handler_installed) + { + __register_atfork (samasan_memory_pool_pause, + samasan_memory_pool_resume, + samasan_memory_pool_resume, + __dso_handle); + fork_handler_installed = true; + } +} + +void +samasan_uninstall_fork_handler (void) +{ + if (fork_handler_installed) + { + UNREGISTER_ATFORK (__dso_handle); + fork_handler_installed = false; + } +} + +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..ce611cbeba --- /dev/null +++ b/sampling-asan/samasan_allocate.h @@ -0,0 +1,69 @@ +/* Prototypes and type definitions for sanitized allocation in the + sampling-asan 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; if not, see + . */ + +#ifndef _SAMASAN_ALLOCATE_H +#define _SAMASAN_ALLOCATE_H + +#include + +/* 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; +}; + +// TODO: change the type of chunk_size +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:31; + 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 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..9317025b14 --- /dev/null +++ b/sampling-asan/samasan_backtrace.c @@ -0,0 +1,58 @@ +/* Definitions for the backtracing feature used in sampling-asan. + 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 "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, + void (*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..cbbf4280b4 --- /dev/null +++ b/sampling-asan/samasan_backtrace.h @@ -0,0 +1,30 @@ +/* Prototypes for the backtrace feature used in sampling-asan. + 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 + . */ + +#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, + void (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..472eebb1f0 --- /dev/null +++ b/sampling-asan/samasan_common.c @@ -0,0 +1,25 @@ +/* Definitions for sampling-asan common functions. + 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 "samasan_common.h" + +bool +samasan_mutex_trylock (struct samasan_mutex *mutex) +{ + return __libc_lock_trylock (mutex->lock); +} diff --git a/sampling-asan/samasan_common.h b/sampling-asan/samasan_common.h new file mode 100644 index 0000000000..e15559c907 --- /dev/null +++ b/sampling-asan/samasan_common.h @@ -0,0 +1,100 @@ +/* Prototypes and definitions for sampling-asan common functions. + 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 + . */ + +#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 */ + +#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_forced_read (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) + +extern SAMASAN_TLS_SPECIFIER bool is_in_samasan; /* defined in samasan_allocate.c */ +#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 { + __libc_lock_define (, lock); +}; + +static inline void +samasan_mutex_init (struct samasan_mutex *mutex) +{ + __libc_lock_init (mutex->lock); +} + +static inline void +samasan_mutex_lock (struct samasan_mutex *mutex) +{ + __libc_lock_lock (mutex->lock); +} + +static inline void +samasan_mutex_unlock (struct samasan_mutex *mutex) +{ + __libc_lock_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..f2c37f5b1f --- /dev/null +++ b/sampling-asan/samasan_error.c @@ -0,0 +1,117 @@ +/* Definitions for the error functions in sampling-asan. + 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 /* 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..270b244f10 --- /dev/null +++ b/sampling-asan/samasan_error.h @@ -0,0 +1,48 @@ +/* Prototypes for the error functions in sampling-asan. + 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 + . */ + +#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); + +#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..1e88e9b07f --- /dev/null +++ b/sampling-asan/samasan_fault_handler.c @@ -0,0 +1,125 @@ +/* Definitions for the sampling-asan fault handler. + 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 "samasan_allocate.h" +#include "samasan_error.h" +#include "samasan_common.h" +#include "samasan_report.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) + { + signal (SIGSEGV, SIG_DFL); + raise (SIGSEGV); + } + else if (default_handler.sa_handler == SIG_IGN) + { + /* This error is not reported by sampling-asan */ + if (error == OUT_OF_MEMORY_POOL || error == UNKNOWN_ERROR) + { + /* Sampling-asan is intended to be used in production system. + So, we don't need to abort the execution of the program. + XXX: is this meaningful? or can be removed? */ + signal (SIGSEGV, SIG_IGN); + 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; + + 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..a3c6f2966d --- /dev/null +++ b/sampling-asan/samasan_fault_handler.h @@ -0,0 +1,24 @@ +/* Prototypes and definition for a sampling-asan fault handler. + 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 + . */ + +#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..8cf1df849b --- /dev/null +++ b/sampling-asan/samasan_init.c @@ -0,0 +1,353 @@ +/* Definitions for sampling-asan initialization. + 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 "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_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_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_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 + +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); + /* on error */ + 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); + /* on error */ + 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; + } + 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); +} + +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_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..607131cf25 --- /dev/null +++ b/sampling-asan/samasan_init.h @@ -0,0 +1,34 @@ +/* Prototypes and definition for sampling-asan initialization. + 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 + . */ + +#ifndef _SAMASAN_INIT_H +#define _SAMASAN_INIT_H + +#include + +extern bool samasan_enabled; + +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..b1bd28f639 --- /dev/null +++ b/sampling-asan/samasan_report.c @@ -0,0 +1,244 @@ +/* Definitions for sampling-asan reporting. + 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 "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 void __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); + + write (fd, buffer, sizeof (buffer)); +#undef BUF_LEN +} + +static void (*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..c92a07a842 --- /dev/null +++ b/sampling-asan/samasan_report.h @@ -0,0 +1,35 @@ +/* Prototypes for sampling-asan reporting. + 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 + . */ + +#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..b8e8e6b318 --- /dev/null +++ b/sampling-asan/samasan_sampling.c @@ -0,0 +1,67 @@ +/* Definitions for the sampling methods in sampling-asan. + 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 "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..130da36dfc --- /dev/null +++ b/sampling-asan/samasan_sampling.h @@ -0,0 +1,28 @@ +/* Prototypes for the sampling-asan sampling methods. + 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 + . */ + +#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..3a5441bc15 --- /dev/null +++ b/sampling-asan/samasan_variable_init.def @@ -0,0 +1,37 @@ +/* Default values of configurables in sampling-asan. + 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 + . */ + +#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" + +/* 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 Sep 25 08:56:00 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: 120829 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 BB726385841D for ; Thu, 25 Sep 2025 09:01:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BB726385841D 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=p0Zpc2Lu 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 1BF32385840C for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1BF32385840C 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 1BF32385840C 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=1758790609; cv=none; b=T9NqCsSPet8HQ86Hc1TutqV5NYLX9hhUF2rtKsTgx7USKe7lY3WaO0i2lXLjfA7mkrBMqTaHUAOo/lXdPhXl5G2BLk+Ihf+6r4gxEd7AEBCgCnLzVrx2c0432pMXPhCTsaY8aeJhy0uK+GzQpx3BsnSVI52Ztl+j1sQQ4WP40OE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=m9e/4WZfJqpCjY/UB2oLWVUO4kW51hExk5gNzWK0vfI=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ss5Bm3teiwvmV4tEWR0g4J/IgFZUHhoPCu1HuVJjfJ8jVm5i7wzQTx08gipZs0NIWf5Q6bmx2uN4QokHMy4rrApf+6P8VzUvMbwlxaxuVrFvHJuC3Wtr98V+jhUO1u6nJT2xVocdYultwAMgLg9Tr8rnpu9Hhx1i6SlIqKs5qrg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1BF32385840C Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp03c8082c395b2e1ed821b021317439d407~oerzClkJD2277022770epoutp03o for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250925085645epoutp03c8082c395b2e1ed821b021317439d407~oerzClkJD2277022770epoutp03o DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=YrcVkPE+k1DX/GoC2hqgx0ADmGd2nUSAJczppYyTrYk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=p0Zpc2LuUnJr3W2H5fpnABzjkqOy2tCiHlvv0kXmzWqWPWmGQYJxGlf1kLyaRMaYn yyk/pGpLaH/SAmxrxZfVOX+JyVFHFVKETOJTdRjVyyoPZ06tgXCxtnHITN9AoybENz 7XCrUzmHDbvtzZPjWlB2Ql6kqKc66pv227ZD/F3c= Received: from epsnrtp02.localdomain (unknown [182.195.42.154]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p339621a06d5da369450983bb1f9e37c44~oeryhf7yZ1125511255epcas1p3t; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p1.samsung.com (unknown [182.195.38.107]) by epsnrtp02.localdomain (Postfix) with ESMTP id 4cXSJD3py4z2SSKX; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p187b73064034ca59723172afd35c12b8a~oerxiAQFx1786917869epcas1p1R; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085643epsmtip191b8c4952f9958a7f1c835a87622e6d2~oerxco7hE0264802648epsmtip1-; Thu, 25 Sep 2025 08:56:43 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 2/9] sampling-asan: Add test cases for sampling-asan Date: Thu, 25 Sep 2025 17:56:00 +0900 Message-Id: <20250925085607.3365493-2-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p187b73064034ca59723172afd35c12b8a X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p187b73064034ca59723172afd35c12b8a References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-12.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_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 | 10 +- sampling-asan/tst-allocate.c | 209 ++++++++++++++++++++++++ sampling-asan/tst-block-sizes.c | 68 ++++++++ sampling-asan/tst-chunk-pick.c | 103 ++++++++++++ sampling-asan/tst-common.c | 88 ++++++++++ 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 ++++++++ 18 files changed, 1522 insertions(+), 1 deletion(-) create mode 100644 sampling-asan/tst-allocate.c create mode 100644 sampling-asan/tst-block-sizes.c create mode 100644 sampling-asan/tst-chunk-pick.c create mode 100644 sampling-asan/tst-common.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 70f639dab5..b0d408af30 100644 --- a/sampling-asan/Makefile +++ b/sampling-asan/Makefile @@ -25,5 +25,13 @@ dist-headers := samasan.h headers := $(dist-headers) routines := samasan_allocate samasan_error samasan_sampling samasan_common \ samasan_init samasan_report samasan_backtrace samasan_fault_handler +tests := tst-allocate tst-sampling tst-threaded-allocation tst-init \ + tst-double-free tst-use-after-free tst-invalid-write \ + tst-block-sizes tst-partition-sizes tst-invalid-access \ + tst-invalid-access2 tst-out-of-memory-pool \ + tst-invalid-free tst-invalid-free2 tst-pause-on-fork \ + tst-chunk-pick -include ../Rules +$(objpfx)tst-threaded-allocation: $(shared-thread-library) + +include ../Rules \ No newline at end of file diff --git a/sampling-asan/tst-allocate.c b/sampling-asan/tst-allocate.c new file mode 100644 index 0000000000..b0598a5fc5 --- /dev/null +++ b/sampling-asan/tst-allocate.c @@ -0,0 +1,209 @@ +/* Test and verify allocations in sampling-asan. + 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 "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..5bf35ab7bc --- /dev/null +++ b/sampling-asan/tst-block-sizes.c @@ -0,0 +1,68 @@ +/* Test and verify various chunk sizes in sampling-asan. + 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 "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-chunk-pick.c b/sampling-asan/tst-chunk-pick.c new file mode 100644 index 0000000000..94793e69d9 --- /dev/null +++ b/sampling-asan/tst-chunk-pick.c @@ -0,0 +1,103 @@ +/* Test and verify memory chunk pick styles defined in sampling-asan. + 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 "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..333ab9d8ab --- /dev/null +++ b/sampling-asan/tst-common.c @@ -0,0 +1,88 @@ +/* Definition of common functions for testing. + 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 + +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-double-free.c b/sampling-asan/tst-double-free.c new file mode 100644 index 0000000000..4ef5f5a62c --- /dev/null +++ b/sampling-asan/tst-double-free.c @@ -0,0 +1,63 @@ +/* Test and verify a double-free case. + 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 "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..45cafd3d69 --- /dev/null +++ b/sampling-asan/tst-init.c @@ -0,0 +1,120 @@ +/* Test and verify initialization in sampling-asan + 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 "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..2105b068d2 --- /dev/null +++ b/sampling-asan/tst-invalid-access.c @@ -0,0 +1,71 @@ +/* Test and verify an invalid-access case. + 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 "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..64cb34c643 --- /dev/null +++ b/sampling-asan/tst-invalid-access2.c @@ -0,0 +1,66 @@ +/* Test and verify an unaligned-access case. + 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 "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..e4a5af4209 --- /dev/null +++ b/sampling-asan/tst-invalid-free.c @@ -0,0 +1,65 @@ +/* Test and verify an invalid-free case. + 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 "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..7ad911ec24 --- /dev/null +++ b/sampling-asan/tst-invalid-free2.c @@ -0,0 +1,65 @@ +/* Test and verify an invalid-free case. + 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 "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..0e3632020f --- /dev/null +++ b/sampling-asan/tst-invalid-write.c @@ -0,0 +1,69 @@ +/* Test and verify allocations in sampling-asan. + 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 "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..cdf89533f7 --- /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) 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 "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..78cdaadaea --- /dev/null +++ b/sampling-asan/tst-partition-sizes.c @@ -0,0 +1,88 @@ +/* Test and verify configurable partition size in sampling-asan + 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 "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..995f0914e5 --- /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) 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 "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..981903469d --- /dev/null +++ b/sampling-asan/tst-sampling.c @@ -0,0 +1,82 @@ +/* Test and verify sampling methods in sampling-asan + 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 "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..c75581ab5b --- /dev/null +++ b/sampling-asan/tst-threaded-allocation.c @@ -0,0 +1,90 @@ +/* Test and verify threaded-allocations in sampling-asan + 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 "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..96e5b0c377 --- /dev/null +++ b/sampling-asan/tst-use-after-free.c @@ -0,0 +1,66 @@ +/* Test and verify a double-free case. + 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 "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 Sep 25 08:56:01 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: 120833 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 8D9C8385841D for ; Thu, 25 Sep 2025 09:06:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8D9C8385841D 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=GH4xK5LO 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 244013858410 for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 244013858410 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 244013858410 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=1758790609; cv=none; b=LEOLQIF70phrSZyBbKLZknSROQUVb3U9oFaOQlgZZqXiRQvqkNpACynnvCtR9ACaC990sp3j8CMepUld8q0gU2OF1aJTfUwfOLoeG1eP/j8OL37yITs1WabO9vkCtOndOvLFfw9RvOgEpwDvORSzXZ2LG6nt2vOnMWi33vhWkrY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=HFT0DugdBG1hFT6dFH4GZ18iW5DdbrY6aUfPBkq/17I=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=apzinI10ewBJAl5RuD2zQAVbNywYsDv+l0/47b6ymDBH6cxsfrCf3XTCOZYit/rRi7TJFdxokuFxl52Rc1ahqKGsAv53SlwEbI8nBcXIONShjrKmRJQ+EJpgnetgrYnen26eqqCmZLFmDN+e5/e8aYWKoN8hgX2alHuOmk/KkzU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 244013858410 Received: from epcas1p1.samsung.com (unknown [182.195.41.45]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp0487c439e9066cad2033a113b03a31672e~oerzNsOMJ1895718957epoutp04o for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250925085645epoutp0487c439e9066cad2033a113b03a31672e~oerzNsOMJ1895718957epoutp04o DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=AjP8RioHZZwvWDz0IpZhGjbD7W+jFatQ+yxggIMFdhQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GH4xK5LOGH9cuWWvuEb+l1YaXfdBywjJv8xNK8bPYOWEXLHOgi59whNPMgOOWqMVr KlsBOW42LNkKTBtaUHe07MY1UOhWn3FTRnwi1bj6prxK+90q8pZW6djF/7BiwrUHG6 lORm1T2BkYtp2R4yvlL5zfzOwIaCdQoUGRzyWTa8= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p4942c094ad0e2aaec84a9157acaf03d82~oeryl8XcS2833028330epcas1p4Q; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.104]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4cXSJD47jWz6B9m6; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p259f52eea345375cf5379f3d141c07188~oerxm1YEs2342323423epcas1p2X; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip1354e096323fbc6637607ca6d288aa265~oerxid1M00321803218epsmtip1v; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 3/9] sampling-asan: Add README.md Date: Thu, 25 Sep 2025 17:56:01 +0900 Message-Id: <20250925085607.3365493-3-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p259f52eea345375cf5379f3d141c07188 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p259f52eea345375cf5379f3d141c07188 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-9.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, 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 | 88 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 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..7f0c08bef1 --- /dev/null +++ b/sampling-asan/README.md @@ -0,0 +1,88 @@ +# Sampling-based address sanitization (sampling-asan) + +Author: Sung-hun Kim (sfoon.kim@samsung.com, sebuns@gmail.com) + +Date: 2025.02.24 + +## 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. + +## How to use 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 Sep 25 08:56:02 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: 120826 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 719C33858436 for ; Thu, 25 Sep 2025 08:58:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 719C33858436 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=B61j834y 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 0DECC3858C74 for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0DECC3858C74 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 0DECC3858C74 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=1758790609; cv=none; b=QdoZOZaEyb3bICcTN3k+nToum6MgTbigcX4XzRghsBMtv253TiZH19TOlNfF7sv3plh5Ynkymw8mc7aSm86NqS0aE5F9JqJd6ubDLmzt6PmQ5ElWMHRBBUu/gMgt46DQwN8+WqSBKHlgkTIXtRtXcaVCr+SjWCoz0Nuo8Z3WQhA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=Yi9m72aqfUVZhg1nSRBnmfAKeCi6crVxkFJEQ7D5pDE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=kylw7WQAxViKpFqGeVZRyJdO74V80fzgGuhc0b+hUikKnz5u0wUpwSFcG1/+qj/DYZpHp7gjRJNktjAIDDGlNlmoiPLO9E3SBRgshhGtDTNsbdlgaZTh66p7WxH7E122C1ptwpmHtpIAtacFFXrq+iwqEt1bYMHjBulmUIFqzGc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0DECC3858C74 Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp0230e0749de11613d837481e22988468fe~oerzIUuMD3089830898epoutp02k for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20250925085645epoutp0230e0749de11613d837481e22988468fe~oerzIUuMD3089830898epoutp02k DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=nC4H3klJYuMIDbLw4mtZNiwWDUrFQ6a0w0Otj74K/PA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B61j834yBoomj6ljwTK6nPzaWI3b2ytCC96xH1Rh+w7c1q0wbDCcYk0LX76L+peGF Wrrllzd+B/2QlTbwP0W3NYDx/p8GAyQ0HSRuK9NUUVwqx+t//4psSlJQgBnju7KIrt zMjoIfYuPGsLcPIUheGxvtjCt2TFMh1E9BUTD9x8= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas1p2.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p22cba7c0a976fd729b9cbc587adab1d82~oeryhrqXZ2712727127epcas1p2i; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.104]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4cXSJD5F71z6B9m6; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p309f38631f97429209e8bae6c3d5a9158~oerxuEtFp0442104421epcas1p3G; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip1dd77936440b229c7856ad46691210f43~oerxnU2CT0289302893epsmtip1A; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 4/9] Makeconfig: Add a sampling-asan directory to the build script Date: Thu, 25 Sep 2025 17:56:02 +0900 Message-Id: <20250925085607.3365493-4-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p309f38631f97429209e8bae6c3d5a9158 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p309f38631f97429209e8bae6c3d5a9158 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-11.4 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 --- Makeconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makeconfig b/Makeconfig index 9eda4fa528..8b90130a2a 100644 --- a/Makeconfig +++ b/Makeconfig @@ -1409,7 +1409,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 From patchwork Thu Sep 25 08:56:03 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: 120830 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 3A384385840C for ; Thu, 25 Sep 2025 09:02:51 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3A384385840C 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=Bar54AMj 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 13C2C3858C2C for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 13C2C3858C2C 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 13C2C3858C2C 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=1758790609; cv=none; b=N1pSNQO94sfw5pfN8v5sXOVeWArueD1DwtfGsNHPcKLiYmvligi7rk58bja/Wp9KWmLKAVl4xhMOFWDhDuWnxJjfHY6St4ggwQ8aKuk5B6/9gxOn/jZtBdmeZVYuHekaUrZo6PZMWzNEu6Zfo/uYTjXbv5L9e6Hxs7k/uY8rocE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=fjoKZ6cguRIbeGrsz3tbPtQuT+amGOEXV6pFl2UJrvY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=VdM9ClFM/8okLg3Zls78Ko1UA5HvyuQ2adEwPGXRBP5znQnbdcbJ55b/PQndqRDi9zZEiKRuwNzXl+t7gMksrF4LgD5VjXw6QK8YerALixTRhc8i3heEtUTHi0JAhGoAzqSYrnSPWIKB0ekCPiAXTJum5MhHIBhj2SOZRY0c7oo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 13C2C3858C2C Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250925085646epoutp04742870969fec7b449d59c02b819a5b70~oerzdNsQE1894818948epoutp04i for ; Thu, 25 Sep 2025 08:56:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250925085646epoutp04742870969fec7b449d59c02b819a5b70~oerzdNsQE1894818948epoutp04i DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790606; bh=2YW/9Q5AABX4VxmG6w8UVmV3hlPRs1sL8O3Pr0M4oq8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Bar54AMjK48Pv2ahX1wswArid05KprrOG5eO3CfMOMhoZM0/AXW8sqv6kGlp3zZVc 5OmVxJKtd5emBEpMT+KGzkZrE3ZScMF7ZANIdXlROHHXM54MVTtVsssHooXHV+mYzx VIdmbUmvL0ZIfqm+Cys//qGdiBTy35W3A3Fp3TdE= Received: from epsnrtp02.localdomain (unknown [182.195.42.154]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p4972e65229c7ac273e18b93a8b979ef18~oery82Rrw2833028330epcas1p4S; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.110]) by epsnrtp02.localdomain (Postfix) with ESMTP id 4cXSJD6XHcz2SSKj; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p1a2b9764b227bb33dcf0577f0099a19d9~oerxzcHH81559615596epcas1p1I; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip1cb84fe648db2d1020a69c7b0084e4b84~oerxuyHCp0166901669epsmtip1i; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 5/9] malloc: Add malloc_sanitize to libc_malloc_debug.so Date: Thu, 25 Sep 2025 17:56:03 +0900 Message-Id: <20250925085607.3365493-5-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p1a2b9764b227bb33dcf0577f0099a19d9 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p1a2b9764b227bb33dcf0577f0099a19d9 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-12.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_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 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. Signed-off-by: Sung-hun Kim --- Rules | 20 +++++ elf/dl-tunables.list | 6 ++ malloc/Makefile | 8 ++ malloc/malloc-debug.c | 18 +++++ malloc/malloc-sanitize.c | 147 +++++++++++++++++++++++++++++++++++ malloc/tst-malloc-sanitize.c | 79 +++++++++++++++++++ 6 files changed, 278 insertions(+) create mode 100644 malloc/malloc-sanitize.c create mode 100644 malloc/tst-malloc-sanitize.c diff --git a/Rules b/Rules index 44c041c491..995773616a 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 @@ -215,6 +217,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) @@ -229,6 +232,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) @@ -303,6 +307,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) \ @@ -358,6 +370,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/malloc/Makefile b/malloc/Makefile index cc012e2921..7cadf4b786 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 diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c index 0bb57841ee..56622eddfa 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 *) = atomic_forced_read (__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); @@ -206,6 +218,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; @@ -324,6 +339,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..21d31fc555 --- /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..4d9424c770 --- /dev/null +++ b/malloc/tst-malloc-sanitize.c @@ -0,0 +1,79 @@ +/* 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; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" From patchwork Thu Sep 25 08:56:04 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: 120828 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 637713858C74 for ; Thu, 25 Sep 2025 09:00:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 637713858C74 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=pLMN1h08 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 1EBBB385840E for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1EBBB385840E 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 1EBBB385840E 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=1758790609; cv=none; b=R8gu4g7z6kZwfCtO/BKTJnMhHXiw6XUJPCTZZ9FWqr0Rm+fzB89vlOv5Ldp3XtcGlrHcw282/8WygiDsg2a4vBEoBGPvd/LqMSio3bNCPoTc7gPHdIkz0Um/mEivduMYVSy6wSrsXuXPaXFeWO9d6oKQjwI1lH4A5KK7uLc2twE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=CdeLzGY/T99VcVy3AjgO5lyK0jXXC1m07RRsEs4xoWY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=kFnhHvKHTJJcNbTCEAQGFx1B9Y7lhM63b4ywkXWzFvEZFC3QrTAkGzIPCQQYvETQS4jMkDvJ//FZmEbsuXraDqK4GLOi2gwIkICMwcz1S3/SeaMTZvOK8/l/9SvRCQk/QowUNlTXSBcXyJIiM3xsY59bJs5e/7/hMHOLuAIVFUs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1EBBB385840E Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp03b700f6bd21d8ec8d60ba866e0ab2f7b7~oerzRKraC2274622746epoutp03y for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250925085645epoutp03b700f6bd21d8ec8d60ba866e0ab2f7b7~oerzRKraC2274622746epoutp03y DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=x6lN8zB2QuAyAEfQ6Q0XLHgVdx9NinlJl5v2AqSS6qY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pLMN1h08FyZlxWyY4bx38NilZYtMedRZfko9cWf/br19q5xbQHgPra1n0pxuVcw4Y 9zhDLSMZ8BAHDGS/M1q2mLWFt2VYI9E3JNrPsmAcZcmSsn7qhVrJVLuhbc0WjZlmHX o6ay0oMQBylkkPCALsB96hbTLqqrrHyiqnaWFo0A= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p3fdd70d8d404a055d5e645b3d93386bfa~oery470e41128511285epcas1p3V; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p3.samsung.com (unknown [182.195.38.99]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4cXSJD6PW9z6B9m4; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p45dc663eb1e7259298e74a1399dc428b9~oerx4o2OS1466414664epcas1p4e; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip13288e0772cdfa3f4f08db9ca79bedd14~oerx0A-ZA0289302893epsmtip1B; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 6/9] sampling-asan: Add a continue-on-crash option Date: Thu, 25 Sep 2025 17:56:04 +0900 Message-Id: <20250925085607.3365493-6-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p45dc663eb1e7259298e74a1399dc428b9 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p45dc663eb1e7259298e74a1399dc428b9 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, PROLO_LEO1, 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 To enhance usability in production environments, I have introduced a continue-on-crash option for sampling-asan. This feature allows the application to restore the running context after encountering bypassable memory bugs, such as use-after-free and invalid- write bugs. By enabling this option, developers can ensure that applications keep their running contexts even they meet memory bugs while developers collect bug reports. This addition makes sampling-asan more practical for production environments. Signed-off-by: Sung-hun Kim --- sampling-asan/Makefile | 2 +- sampling-asan/README.md | 6 ++ sampling-asan/samasan_allocate.c | 41 +++++++++ sampling-asan/samasan_allocate.h | 5 +- sampling-asan/samasan_error.h | 5 ++ sampling-asan/samasan_fault_handler.c | 21 +++-- sampling-asan/samasan_init.c | 19 ++++ sampling-asan/samasan_init.h | 1 + sampling-asan/samasan_variable_init.def | 1 + sampling-asan/tst-bypass-block.c | 68 ++++++++++++++ sampling-asan/tst-continue-on-crash.c | 113 ++++++++++++++++++++++++ 11 files changed, 271 insertions(+), 11 deletions(-) create mode 100644 sampling-asan/tst-bypass-block.c create mode 100644 sampling-asan/tst-continue-on-crash.c diff --git a/sampling-asan/Makefile b/sampling-asan/Makefile index b0d408af30..b040a5ede9 100644 --- a/sampling-asan/Makefile +++ b/sampling-asan/Makefile @@ -30,7 +30,7 @@ tests := tst-allocate tst-sampling tst-threaded-allocation tst-init \ tst-block-sizes tst-partition-sizes tst-invalid-access \ tst-invalid-access2 tst-out-of-memory-pool \ tst-invalid-free tst-invalid-free2 tst-pause-on-fork \ - tst-chunk-pick + tst-chunk-pick tst-continue-on-crash tst-bypass-block $(objpfx)tst-threaded-allocation: $(shared-thread-library) diff --git a/sampling-asan/README.md b/sampling-asan/README.md index 7f0c08bef1..6ec217c2ad 100644 --- a/sampling-asan/README.md +++ b/sampling-asan/README.md @@ -3,6 +3,7 @@ Author: Sung-hun Kim (sfoon.kim@samsung.com, sebuns@gmail.com) Date: 2025.02.24 +Updated: 2025.09.12 ## Overview @@ -61,6 +62,11 @@ 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 diff --git a/sampling-asan/samasan_allocate.c b/sampling-asan/samasan_allocate.c index c021523e56..75857f922d 100644 --- a/sampling-asan/samasan_allocate.c +++ b/sampling-asan/samasan_allocate.c @@ -150,6 +150,22 @@ 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) @@ -219,6 +235,31 @@ unprotect_range_in_block (void *start, size_t 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. diff --git a/sampling-asan/samasan_allocate.h b/sampling-asan/samasan_allocate.h index ce611cbeba..4f5195a58f 100644 --- a/sampling-asan/samasan_allocate.h +++ b/sampling-asan/samasan_allocate.h @@ -32,13 +32,13 @@ struct memory_pool_trace { uint64_t tid; }; -// TODO: change the type of chunk_size 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:31; + uint32_t chunk_size:30; + bool is_bypassed:1; bool is_free:1; }; @@ -55,6 +55,7 @@ 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); diff --git a/sampling-asan/samasan_error.h b/sampling-asan/samasan_error.h index 270b244f10..dcf5af728d 100644 --- a/sampling-asan/samasan_error.h +++ b/sampling-asan/samasan_error.h @@ -45,4 +45,9 @@ extern void raise_fault_with_address (samasan_error_t error, 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 index 1e88e9b07f..4e30eae707 100644 --- a/sampling-asan/samasan_fault_handler.c +++ b/sampling-asan/samasan_fault_handler.c @@ -22,6 +22,7 @@ #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; @@ -54,6 +55,7 @@ segfault_handler (int sig, siginfo_t *info, void *context) 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, @@ -61,21 +63,23 @@ segfault_handler (int sig, siginfo_t *info, void *context) /* 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)) { signal (SIGSEGV, SIG_DFL); raise (SIGSEGV); } + } else if (default_handler.sa_handler == SIG_IGN) { /* This error is not reported by sampling-asan */ - if (error == OUT_OF_MEMORY_POOL || error == UNKNOWN_ERROR) - { - /* Sampling-asan is intended to be used in production system. - So, we don't need to abort the execution of the program. - XXX: is this meaningful? or can be removed? */ - signal (SIGSEGV, SIG_IGN); - raise (SIGSEGV); - } + signal (SIGSEGV, SIG_IGN); + raise (SIGSEGV); } else { @@ -96,6 +100,7 @@ install_signal_handler (void) 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); diff --git a/sampling-asan/samasan_init.c b/sampling-asan/samasan_init.c index 8cf1df849b..c703674544 100644 --- a/sampling-asan/samasan_init.c +++ b/sampling-asan/samasan_init.c @@ -39,6 +39,7 @@ typedef enum samasan_option { SAMASAN_PARTITION_SIZE, SAMASAN_PAUSE_ON_FORK, SAMASAN_CHUNK_PICK, + SAMASAN_CONTINUE_ON_CRASH, SAMASAN_OPTIONS, } samasan_option_t; @@ -51,6 +52,7 @@ static const char *options_string[SAMASAN_OPTIONS + 1] = { "SAMASAN_PARTITION_SIZE", "SAMASAN_PAUSE_ON_FORK", "SAMASAN_CHUNK_PICK", + "SAMASAN_CONTINUE_ON_CRASH", "SAMASAN_OPTIONS", }; @@ -72,6 +74,8 @@ struct samasan_configurable { 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) @@ -133,6 +137,8 @@ samasan_set_variable_range (samasan_option_t option, uint32_t max, 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) @@ -217,6 +223,15 @@ import_samasan_variable (int type, const char *val) 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; @@ -277,6 +292,8 @@ samasan_variable_init (void) 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 @@ -324,6 +341,8 @@ samasan_init (void) 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; diff --git a/sampling-asan/samasan_init.h b/sampling-asan/samasan_init.h index 607131cf25..971590eeca 100644 --- a/sampling-asan/samasan_init.h +++ b/sampling-asan/samasan_init.h @@ -22,6 +22,7 @@ #include extern bool samasan_enabled; +extern bool samasan_continue_on_crash; static __inline __attribute__ ((always_inline)) bool is_samasan_enabled (void) diff --git a/sampling-asan/samasan_variable_init.def b/sampling-asan/samasan_variable_init.def index 3a5441bc15..b92feb1701 100644 --- a/sampling-asan/samasan_variable_init.def +++ b/sampling-asan/samasan_variable_init.def @@ -24,6 +24,7 @@ #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" diff --git a/sampling-asan/tst-bypass-block.c b/sampling-asan/tst-bypass-block.c new file mode 100644 index 0000000000..67d2e8ae82 --- /dev/null +++ b/sampling-asan/tst-bypass-block.c @@ -0,0 +1,68 @@ +/* Test and verify a double-free case. + 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 "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-continue-on-crash.c b/sampling-asan/tst-continue-on-crash.c new file mode 100644 index 0000000000..28926d2e83 --- /dev/null +++ b/sampling-asan/tst-continue-on-crash.c @@ -0,0 +1,113 @@ +/* Test and verify an invalid-access case. + 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 "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 From patchwork Thu Sep 25 08:56:05 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: 120831 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 3E7683858C5E for ; Thu, 25 Sep 2025 09:03:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3E7683858C5E 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=MWXjsse+ 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 1941F3858406 for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1941F3858406 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 1941F3858406 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=1758790609; cv=none; b=YnYbZ+fC7WZDVUSQhP5izQGchaFE7qmnUQOri5jL6s32Pd8IcdboiTQqGJcSh2qkKqSTlPB/3Y1U4L8Ry1k8gTT0nsRiCwFTcPpYu2Jv85mc/sYsxK4Ik9FvvmvTqWmFBhSoyZOQS5xPXZg/MFsllZMIqJ+obFP+QhxKfR1EnEw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=caDDm3gEXy+63+Jseu35aScTiG/amuItcoiuXznNH7Y=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=inmMiv6yRpM8bPY7XGb627K8vNaKStAGdQY1ZNRLCjaaY43acL/EAYUi6OtzqLBKGMd9lYGRtKFNx1vmC8DlgmQ2yYm0Xoa0bnxik7FQg3bNWp7SPr5YM3GDg13E1+fRgwBiTXH7y9ZYRrTGWzy49VtAID+PHOyP0XXz7okU4SE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1941F3858406 Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250925085645epoutp04e51758c019525b92dd5beb2c639c8675~oerzKAboO1895418954epoutp04m for ; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250925085645epoutp04e51758c019525b92dd5beb2c639c8675~oerzKAboO1895418954epoutp04m DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790605; bh=ZQbW1PsWDajOjvpwVGpBvLiFI9nq4xOwqRPVIIf+VHA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MWXjsse+0XvE83+RSnNYv46tQPoYjMmb9YXDshrofVFGziOX28PaO6W6YPjnfDm3d K3onsxMtzd47DbDcCCTel+t+v2kljcmLkClLQXYM31sd9sbUNWUOwQP18NGXW5XzTk jUzGp7Qm6Ow7qCmaryP3CyHAgsOdGbXQ8Ztgrt/4= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p3186cd94d0862e122ff878a71333c280a~oery7BxEy1125511255epcas1p3w; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p1.samsung.com (unknown [182.195.38.109]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4cXSJD6mlVz6B9m7; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p41af420f8438d4c18424d10a1faab7119~oerx9kOYS2833028330epcas1p4L; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip1d4131525090f45ede0309e92ce79610f~oerx5S0mF0321803218epsmtip1w; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 7/9] manual: Add descriptions for sampling-asan in the manual Date: Thu, 25 Sep 2025 17:56:05 +0900 Message-Id: <20250925085607.3365493-7-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p41af420f8438d4c18424d10a1faab7119 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p41af420f8438d4c18424d10a1faab7119 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-11.8 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 | 141 +++++++++++++++++++++++++++++++++++++++++++ manual/tunables.texi | 13 ++++ 2 files changed, 154 insertions(+) diff --git a/manual/memory.texi b/manual/memory.texi index 6a70168e61..7ccf1f02c6 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 Debug:: Debugging wrong memory allocation/free/accesses. @end menu Memory mapped I/O is not discussed in this chapter. @xref{Memory-mapped I/O}. @@ -3632,8 +3633,148 @@ 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 a backend for +@code{libc_malloc_debug.so}. +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 Sep 25 08:56:06 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: 120832 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 11978385840E for ; Thu, 25 Sep 2025 09:05:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 11978385840E 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=iDwcVyrS 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 10F9B3858C78 for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 10F9B3858C78 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 10F9B3858C78 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=1758790609; cv=none; b=RswWdJnSTvAWb+VtEpSFL251jxmu1DAQ5vaN7GleHe1LITSThpXSJLI8yUorc7QnKx3UutyabEjkjnN+dVTRF4HkoJyc+V/9t4F/gww7Mr0kqyMpaue62VYMQYkVK+v8+ljaxmmxxqrNBNBWOHKnH43ovfPObImM9tOyv+hYB9o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=HDmZmfFD7hm0kdykH8+gq32QZKBpI70JxwBLOYKzX2E=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=mCsJP2ReYIoi2NEHHYsfww0vuiESi2K0+RcyP8150iu2kPBjuWLywhrZLZJLe1eg1ft4bepI2W0FX6IlmHxRv5mD8M6Xg3wffBHPkNANDTnFoxaPOmBoAZpB84CqbGqwU+noeiz+8Vj5eP2WXzT3wuSNY3V0T1PyHlFoal8OnWs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 10F9B3858C78 Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout2.samsung.com (KnoxPortal) with ESMTP id 20250925085646epoutp0211bb72d2d37fdd8321e8e2737d5f6d67~oerzfv6ul2990129901epoutp02c for ; Thu, 25 Sep 2025 08:56:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.samsung.com 20250925085646epoutp0211bb72d2d37fdd8321e8e2737d5f6d67~oerzfv6ul2990129901epoutp02c DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790606; bh=jxioCybQcSQqfzW7KnpBqwaBn/LuEGsHHQt9ujNpbwc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iDwcVyrSOjIawBZbD6ALtOzkm6eLVG+RZ2xkjSdt7MbGo/ayOCx2LVr/eNA1BtlGx RDuwuzCMutxRLXIz7CsolrRIjB6iPDlQC8QqNyJRErjGrIUzmtnz638uf+BkmoPCTG lcnK1vDZ0ATerTdP5hEAXWVPMDMOiKQcAvumJHbo= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPS id 20250925085645epcas1p4d617dd52d981b50f19ae0f03778c8e48~oerzJEGjv1465614656epcas1p4S; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epcas1p1.samsung.com (unknown [182.195.38.104]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4cXSJF1QRTz6B9m6; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p4.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p4f78007f5ce901acff2436fabb106e8f9~oeryDZmCo1466414664epcas1p4h; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip1cb0feda78e2db62f41e5f9fe0f280399~oerx_UsOB0289402894epsmtip1B; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 8/9] sampling-asan: Obey the GNU coding style Date: Thu, 25 Sep 2025 17:56:06 +0900 Message-Id: <20250925085607.3365493-8-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p4f78007f5ce901acff2436fabb106e8f9 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p4f78007f5ce901acff2436fabb106e8f9 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_MSPIKE_H5, 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 There is no functional change. Signed-off-by: Sung-hun Kim --- sampling-asan/samasan_allocate.c | 13 ++-- sampling-asan/samasan_common.h | 6 +- sampling-asan/samasan_fault_handler.c | 10 +-- sampling-asan/samasan_init.c | 38 ++++++------ sampling-asan/samasan_report.c | 87 ++++++++++++++++----------- sampling-asan/tst-allocate.c | 4 +- sampling-asan/tst-block-sizes.c | 2 +- sampling-asan/tst-chunk-pick.c | 11 ++-- sampling-asan/tst-common.c | 6 +- sampling-asan/tst-continue-on-crash.c | 2 +- sampling-asan/tst-init.c | 14 ++--- sampling-asan/tst-partition-sizes.c | 18 +++--- sampling-asan/tst-pause-on-fork.c | 6 +- 13 files changed, 121 insertions(+), 96 deletions(-) diff --git a/sampling-asan/samasan_allocate.c b/sampling-asan/samasan_allocate.c index 75857f922d..77db975e40 100644 --- a/sampling-asan/samasan_allocate.c +++ b/sampling-asan/samasan_allocate.c @@ -152,8 +152,8 @@ get_next_memory_pool_entry_from_pointer (void *ptr) /* 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) +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; @@ -266,7 +266,7 @@ bypass_block (struct memory_pool_entry_info *entry) 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 + 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; @@ -280,7 +280,7 @@ static memory_chunk_pick_style_t chunk_pick_style; (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)) +#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) @@ -350,7 +350,8 @@ check_guard_pattern (void *chunk, size_t size) address < (entry->address + entry->chunk_size)) bool -is_out_of_chunk_access (uintptr_t address, struct memory_pool_entry_info *entry) +is_out_of_chunk_access (uintptr_t address, + struct memory_pool_entry_info *entry) { if (!is_address_in_chunk (address, entry)) return true; @@ -556,7 +557,7 @@ memory_pool_metadata_init (void) * memory_pool_size); for (size_t i = 0; i < memory_pool_size; i++) { - memory_pool_metadata[i].is_free = true; + memory_pool_metadata[i].is_free = true; if (SAMASAN_UNLIKELY (!free_list_head)) free_list_head = &memory_pool_metadata[i]; else diff --git a/sampling-asan/samasan_common.h b/sampling-asan/samasan_common.h index e15559c907..ae6e919c06 100644 --- a/sampling-asan/samasan_common.h +++ b/sampling-asan/samasan_common.h @@ -27,7 +27,7 @@ #include /* for atomic operations */ #define SAMASAN_TLS_SPECIFIER __thread \ - __attribute__((tls_model("initial-exec"))) + __attribute__ ((tls_model ("initial-exec"))) #define SAMASAN_UNLIKELY(cond) __builtin_expect (!!(cond), 0) #define SAMASAN_LIKELY(cond) __builtin_expect (!!(cond), 1) @@ -37,7 +37,9 @@ #define samasan_atomic_inc(var) atomic_fetch_add_release (var, 1) #define samasan_atomic_dec(var) atomic_fetch_add_release (var, -1) -extern SAMASAN_TLS_SPECIFIER bool is_in_samasan; /* defined in samasan_allocate.c */ +/* 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 diff --git a/sampling-asan/samasan_fault_handler.c b/sampling-asan/samasan_fault_handler.c index 4e30eae707..8154df4292 100644 --- a/sampling-asan/samasan_fault_handler.c +++ b/sampling-asan/samasan_fault_handler.c @@ -42,10 +42,12 @@ segfault_handler (int sig, siginfo_t *info, void *context) 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; - } + 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) diff --git a/sampling-asan/samasan_init.c b/sampling-asan/samasan_init.c index c703674544..5a09959dc5 100644 --- a/sampling-asan/samasan_init.c +++ b/sampling-asan/samasan_init.c @@ -103,14 +103,14 @@ samasan_set_variable_char (samasan_option_t option, const char *value) static inline void samasan_set_variable_range (samasan_option_t option, uint32_t max, - uint32_t min) + uint32_t min) { samasan_configurables[option].range.max = max; samasan_configurables[option].range.min = min; } #define samasan_set_variable(index, value) \ - _Generic((value), \ + _Generic ((value), \ uint32_t: samasan_set_variable_uint, \ const char *: samasan_set_variable_char, \ char *: samasan_set_variable_char, \ @@ -157,7 +157,6 @@ import_samasan_variable (int type, const char *val) case SAMASAN_MAX_ALLOC_SIZE: { uint32_t converted = (uint32_t) atoi (val); - /* on error */ if (!converted) return false; if (!samasan_check_variable_range (SAMASAN_MAX_ALLOC_SIZE, converted)) @@ -168,11 +167,10 @@ import_samasan_variable (int type, const char *val) case SAMASAN_MAX_ON_GOING_ALLOCATIONS: { uint32_t converted = (uint32_t) atoi (val); - /* on error */ if (!converted) return false; if (!samasan_check_variable_range (SAMASAN_MAX_ON_GOING_ALLOCATIONS, - converted)) + converted)) return false; samasan_set_variable (SAMASAN_MAX_ON_GOING_ALLOCATIONS, converted); break; @@ -204,16 +202,16 @@ import_samasan_variable (int type, const char *val) case SAMASAN_PAUSE_ON_FORK: { bool var = false; - if (!strcmp (val, "on") || !strcmp (val, "enable") - || !strcmp (val, "yes") || !strcmp (val, "true")) + if (!strcmp (val, "on") || !strcmp (val, "enable") + || !strcmp (val, "yes") || !strcmp (val, "true")) var = true; - samasan_set_variable (SAMASAN_PAUSE_ON_FORK, var); - break; + samasan_set_variable (SAMASAN_PAUSE_ON_FORK, var); + break; } case SAMASAN_CHUNK_PICK: { uint32_t pick; - if (!strcmp (val, "left") || !strcmp (val, "LEFT")) + 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; @@ -221,17 +219,17 @@ import_samasan_variable (int type, const char *val) pick = (uint32_t) PICK_CENTER; else return false; - samasan_set_variable (SAMASAN_CHUNK_PICK, pick); - break; + 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")) + if (!strcmp (val, "on") || !strcmp (val, "enable") + || !strcmp (val, "yes") || !strcmp (val, "true")) var = true; - samasan_set_variable (SAMASAN_CONTINUE_ON_CRASH, var); - break; + samasan_set_variable (SAMASAN_CONTINUE_ON_CRASH, var); + break; } default: break; @@ -266,10 +264,10 @@ samasan_variable_init (void) MAX_SAMASAN_SAMPLING_RATE, MIN_SAMASAN_SAMPLING_RATE); import_samasan_variable_range (SAMASAN_MAX_ALLOC_SIZE, - MAX_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, + MAX_SAMASAN_MAX_ON_GOING_ALLOCATIONS, MIN_SAMASAN_MAX_ON_GOING_ALLOCATIONS); import_samasan_variable_range (SAMASAN_PARTITION_SIZE, MAX_SAMASAN_PARTITION_SIZE, @@ -281,9 +279,9 @@ samasan_variable_init (void) import_samasan_variable (SAMASAN_SAMPLING_RATE, DEFAULT_SAMASAN_SAMPLING_RATE); import_samasan_variable (SAMASAN_MAX_ALLOC_SIZE, - DEFAULT_SAMASAN_MAX_ALLOC_SIZE); + DEFAULT_SAMASAN_MAX_ALLOC_SIZE); import_samasan_variable (SAMASAN_MAX_ON_GOING_ALLOCATIONS, - DEFAULT_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, diff --git a/sampling-asan/samasan_report.c b/sampling-asan/samasan_report.c index b1bd28f639..0adb6df4a4 100644 --- a/sampling-asan/samasan_report.c +++ b/sampling-asan/samasan_report.c @@ -127,29 +127,36 @@ samasan_report_write (samasan_error_t error, uintptr_t address, 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, + "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, + "=============================================\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, + "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"); + 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); + 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) { @@ -160,28 +167,35 @@ samasan_report_write (samasan_error_t error, uintptr_t address, 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); + diff, direction); } - report_printf (stream, "=============================================\n"); + 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, + "=============================================\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); + 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); + report_printf (stream, + "\n", + entry->deallocation_trace.tid); print_backtrace (&entry->deallocation_trace, stream, report_printf); } if (entry_at_next == NULL) @@ -190,33 +204,38 @@ samasan_report_write (samasan_error_t error, uintptr_t address, 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, + "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); + 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); + 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); + 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); + 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_printf (stream, "\n", + entry->deallocation_trace.tid); + print_backtrace (&entry->deallocation_trace, stream, report_printf); + } } report_end: diff --git a/sampling-asan/tst-allocate.c b/sampling-asan/tst-allocate.c index b0598a5fc5..c5caf14710 100644 --- a/sampling-asan/tst-allocate.c +++ b/sampling-asan/tst-allocate.c @@ -32,7 +32,7 @@ test_allocations (void) void *ptr; ptr = samasan_allocate (zero_size); - TEST_VERIFY(ptr == NULL); + TEST_VERIFY (ptr == NULL); ptr = samasan_allocate (allocation_size); TEST_VERIFY (ptr != NULL); samasan_free (ptr); @@ -102,7 +102,7 @@ test_allocation_use_free_repeat (void) cptr = (char *) ptr; for (int j = 0; j < allocation_size; j++) cptr[j] = 'a'; - samasan_free( ptr); + samasan_free (ptr); } #undef NR_REPEAT } diff --git a/sampling-asan/tst-block-sizes.c b/sampling-asan/tst-block-sizes.c index 5bf35ab7bc..18e96ce5b2 100644 --- a/sampling-asan/tst-block-sizes.c +++ b/sampling-asan/tst-block-sizes.c @@ -33,7 +33,7 @@ test_multiple_chunk_sizes (size_t size) const size_t increase = 64; size_t allocation_size = increase; - sprintf(chunk_size, "%ld", size); + sprintf (chunk_size, "%ld", size); setenv ("SAMASAN_MAX_ALLOC_SIZE", chunk_size, 1/* replace */); samasan_init (); TEST_VERIFY (samasan_is_enabled () == true); diff --git a/sampling-asan/tst-chunk-pick.c b/sampling-asan/tst-chunk-pick.c index 94793e69d9..041e2bdaad 100644 --- a/sampling-asan/tst-chunk-pick.c +++ b/sampling-asan/tst-chunk-pick.c @@ -28,12 +28,13 @@ static const size_t page_size = 4096; static bool -check_allocation_align (memory_chunk_pick_style_t style, size_t size, void *ptr) +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) { /* If style == PICK_FROM_LEFT, the address should be same to * the address of the memory block. */ @@ -74,7 +75,7 @@ test_memory_chunk_pick_style (memory_chunk_pick_style_t style) else setenv ("SAMASAN_CHUNK_PICK", "CENTER", 1); - samasan_init(); + samasan_init (); ptr = samasan_allocate (alloc_size); TEST_VERIFY (ptr != NULL); @@ -94,7 +95,9 @@ do_test (void) So, deinitialize sampling-asan before starting the test */ samasan_deinit (); - for (memory_chunk_pick_style_t style = PICK_FROM_LEFT; style < PICK_END; style++) + for (memory_chunk_pick_style_t style = PICK_FROM_LEFT; + style < PICK_END; + style++) test_memory_chunk_pick_style (style); return 0; diff --git a/sampling-asan/tst-common.c b/sampling-asan/tst-common.c index 333ab9d8ab..64c5a33bdc 100644 --- a/sampling-asan/tst-common.c +++ b/sampling-asan/tst-common.c @@ -33,7 +33,7 @@ check_report (const char *keyword, const char *report_path) if (report != NULL) { char buf[255], *substr; - while (fscanf (report, "%s", buf) != EOF) + while (fscanf (report, "%s", buf) != EOF) { substr = strstr (buf, keyword); if (substr != NULL && !strncmp (substr, keyword, strlen (keyword))) @@ -67,13 +67,13 @@ clean_up_report (const char *report_path) static void test_bed (void (*error_func) (void), const char *keyword, - const char *report_path) + const char *report_path) { pid_t child_pid; clean_up_report (report_path); - child_pid = _Fork(); + child_pid = _Fork (); TEST_VERIFY_EXIT (child_pid != -1); if (child_pid == 0) diff --git a/sampling-asan/tst-continue-on-crash.c b/sampling-asan/tst-continue-on-crash.c index 28926d2e83..27d83e8d01 100644 --- a/sampling-asan/tst-continue-on-crash.c +++ b/sampling-asan/tst-continue-on-crash.c @@ -42,7 +42,7 @@ check_report (const char *keyword, const char *report_path) if (report != NULL) { char buf[255], *substr; - while (fscanf (report, "%s", buf) != EOF) + while (fscanf (report, "%s", buf) != EOF) { substr = strstr (buf, keyword); if (substr != NULL && !strncmp (substr, keyword, strlen (keyword))) diff --git a/sampling-asan/tst-init.c b/sampling-asan/tst-init.c index 45cafd3d69..5cae7d6d61 100644 --- a/sampling-asan/tst-init.c +++ b/sampling-asan/tst-init.c @@ -28,7 +28,7 @@ static void test_repeated_init_and_deinit (void) { #define REPEATS 100 - setenv("SAMASAN_ENABLE", "true", 1/* replace */); + setenv ("SAMASAN_ENABLE", "true", 1/* replace */); for (int i = 0; i < REPEATS; i++) { @@ -44,10 +44,10 @@ static void test_misconfigurations (void) { setenv ("SAMASAN_ENABLE", - "truth" /* should be "yes" or "true" or "enable" or "on" */, - 1 /* replace */); + "truth" /* should be "yes" or "true" or "enable" or "on" */, + 1 /* replace */); setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096" /* exceed the upper limit */, - 1 /* replace */); + 1 /* replace */); setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); @@ -56,7 +56,7 @@ test_misconfigurations (void) setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); setenv ("SAMASAN_MAX_ALLOC_SIZE", "409600" /* exceed the upper limit */, - 1 /* replace */); + 1 /* replace */); setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); @@ -66,7 +66,7 @@ test_misconfigurations (void) 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 */); + "100000" /* exceed the upper limit */, 1 /* replace */); setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); samasan_init (); @@ -86,7 +86,7 @@ test_multiple_inits (void) { setenv ("SAMASAN_ENABLE", "true", 1 /* replace */); setenv ("SAMASAN_MAX_ALLOC_SIZE", "4096" /* exceed the upper limit */, - 1 /* replace */); + 1 /* replace */); setenv ("SAMASAN_MAX_ON_GOING_ALLOCATIONS", "100", 1 /* replace */); setenv ("SAMASAN_SAMPLING_RATE", "1.0", 1 /* replace */); diff --git a/sampling-asan/tst-partition-sizes.c b/sampling-asan/tst-partition-sizes.c index 78cdaadaea..213c424b76 100644 --- a/sampling-asan/tst-partition-sizes.c +++ b/sampling-asan/tst-partition-sizes.c @@ -35,10 +35,10 @@ test_partition_size (size_t partition_size) char *cptr; sprintf (buf, "%ld", partition_size); - setenv("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); + setenv ("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); samasan_init (); - TEST_VERIFY (samasan_is_enabled()); + TEST_VERIFY (samasan_is_enabled ()); for (size_t i = 0; i < 10; i++) { ptr[i] = samasan_allocate (allocation_size); @@ -48,7 +48,7 @@ test_partition_size (size_t partition_size) } for (size_t i = 0; i < 10; i++) samasan_free (ptr[i]); - samasan_deinit(); + samasan_deinit (); } static void @@ -57,10 +57,10 @@ test_wrong_partition_size (size_t partition_size) char buf[100]; sprintf (buf, "%ld", partition_size); - setenv("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); + setenv ("SAMASAN_PARTITION_SIZE", buf, 1/* replace */); samasan_init (); - TEST_VERIFY (!samasan_is_enabled()); + TEST_VERIFY (!samasan_is_enabled ()); } static int @@ -68,13 +68,13 @@ 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 */); + 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(); + samasan_deinit (); for (size_t i = 0; i <= 10; i++) test_partition_size (page_size * i); diff --git a/sampling-asan/tst-pause-on-fork.c b/sampling-asan/tst-pause-on-fork.c index 995f0914e5..174bb9e120 100644 --- a/sampling-asan/tst-pause-on-fork.c +++ b/sampling-asan/tst-pause-on-fork.c @@ -68,10 +68,10 @@ test_pthread_fork (bool memory_pool_resume) else thread_id = xpthread_create (NULL, &memory_pool_stay_pause, NULL); - xpthread_mutex_lock (&mutex); + xpthread_mutex_lock (&mutex); while (!thread_ready) xpthread_cond_wait (&cond, &mutex); - xpthread_mutex_unlock (&mutex); + xpthread_mutex_unlock (&mutex); if (!memory_pool_resume) alarm (1); @@ -85,7 +85,7 @@ test_pthread_fork (bool memory_pool_resume) 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) From patchwork Thu Sep 25 08:56:07 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: 120827 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 A66A2385841D for ; Thu, 25 Sep 2025 08:59:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A66A2385841D 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=m8rtPjfk 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 21758385840F for ; Thu, 25 Sep 2025 08:56:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 21758385840F 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 21758385840F 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=1758790609; cv=none; b=RHD+QMaFp2KrFNJ/TBlm2WIvwHjT7+GbxM8rDA/Br6p50OE+Xy0ihexI7VlFsPpPqk+WTq7Qv3Z0yBI4cI6Dncg2rxZ7Xp+XcafkEdZKwf1Gzd4z0Djws6pmVBDN2EKlLSt98acEJyL7oThe7PcQqoDTxPrO/ktwc18KFcThaiY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1758790609; c=relaxed/simple; bh=8qULjSRBQ3fcJ5IHljNn7HquU3LV5scRyziJ0qmGgi0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=a/FrPaITjfSwuZfaiEoqvgM8D9rJH2nvT86B2hMVdFWUKlyctJrMco1xtdYdF2J5ijiAmi8O+2bpWXa6YbsiK23+bvNBh/eIaaBIILNqoSSh04yd4yQwMmwFYzGcSLBNaCx2TSQoGaqBkn4zgDrDlZwB2DUtoapnt2QjtH2djx4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 21758385840F Received: from epcas1p4.samsung.com (unknown [182.195.41.48]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250925085646epoutp032ef4e46e25adb4c15ed478edac67a009~oerztRmai2275122751epoutp03r for ; Thu, 25 Sep 2025 08:56:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250925085646epoutp032ef4e46e25adb4c15ed478edac67a009~oerztRmai2275122751epoutp03r DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1758790606; bh=GG4RnJYVZkRvk5UYgIp/Y1IRiPIVli8DPT24sCWdKaw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=m8rtPjfks+eor51cFIoE7O4CrDTpEI7YfIBgbdJOhx25Hx/VggPBWOTVZxFiHWJP7 mVP0VCVMDtKGsYzOkmMjmO1cuj15iLANVVAx5LeB0YUgS4/Ifk2s4rkpFASG5JxTAa Un8WPMawhHUmtH2p/qnpe0rwS2SJgZqJ6cgJMzec= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas1p1.samsung.com (KnoxPortal) with ESMTPS id 20250925085646epcas1p153e5ed0ae196d07c476daa7d5bd2449a~oerzb-k161786917869epcas1p1a; Thu, 25 Sep 2025 08:56:46 +0000 (GMT) Received: from epcas1p4.samsung.com (unknown [182.195.38.99]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4cXSJF2wmhz6B9mC; Thu, 25 Sep 2025 08:56:45 +0000 (GMT) Received: from epsmtip1.samsung.com (unknown [182.195.34.30]) by epcas1p3.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epcas1p3ca0a0ac97daabeb4ea6def2a917dcae6~oeryKhvk91121311213epcas1p3_; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) Received: from localhost.localdomain (unknown [10.113.111.45]) by epsmtip1.samsung.com (KnoxPortal) with ESMTPA id 20250925085644epsmtip161554a68e35a55979e6feb07d2077aa4~oeryDzYiv0264802648epsmtip1A; Thu, 25 Sep 2025 08:56:44 +0000 (GMT) From: Sung-hun Kim To: libc-alpha@sourceware.org Cc: 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 v2 9/9] NEWS: Add a new feature sampling-asan Date: Thu, 25 Sep 2025 17:56:07 +0900 Message-Id: <20250925085607.3365493-9-sfoon.kim@samsung.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20250925085607.3365493-1-sfoon.kim@samsung.com> MIME-Version: 1.0 X-CMS-MailID: 20250925085644epcas1p3ca0a0ac97daabeb4ea6def2a917dcae6 X-Msg-Generator: CA CMS-TYPE: 101P cpgsPolicy: CPGSC10-361,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250925085644epcas1p3ca0a0ac97daabeb4ea6def2a917dcae6 References: <20250925085607.3365493-1-sfoon.kim@samsung.com> X-Spam-Status: No, score=-11.6 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 --- NEWS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NEWS b/NEWS index 9831f7f5d4..d68bc7581f 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,13 @@ Major new features: [Add new features here] +* 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