最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c - False positives with Clang CFI sanitizer and array of functions - Stack Overflow

programmeradmin2浏览0评论

This is a follow-up related to Inconsistent false positives with Clang CFI sanitizer and function pointers, but it is for a separate issue

Issue

Background

I have an array of structs which store function pointers, which I loop over and call (my real code is more complex than the sample given). To ensure correct behaviour, I enabled CFI with -fsanitize=cfi -fvisiblity=hidden -flto -fcf-protection=full.

I then started to encounter false positives, where CFI is trapping upon calling these function pointers. These only seem to occur on compilers clang-11 through clang-15 (I will use clang-15). This also only occurs when -fsanitize=cfi, -fcf-protection=full are used together.

Issue

Upon calling the first function pointer, it seems to jump to the wrong address, which immediately causes a trap:

$ clang-15 -o main main.c -Wall -Wextra -Wpedantic -O3 -fsanitize=cfi -fvisibility=hidden -flto -fcf-protection=full
$ gdb ./main -ex run

Program received signal SIGTRAP, Trace/breakpoint trap.
0x000000000040123b in func_a ()
(gdb) where
#0  0x000000000040123b in func_a ()
Backtrace stopped: Cannot access memory at address 0xffffde57
(gdb) 

This issue only occurs when I have more than one function in the array - with a single function it works fine, but multiple functions always causes a trap.

Looking at the disassembly, it appears that in the single case, clang just inlines the call, which is why the issue only occurs with multiple elements in the array.

My question is: why is this happening, and is it a bug in my code, or in clang?

My System

$ uname -srvpio
Linux 6.9.3-76060903-generic #202405300957~1736980680~22.04~44ea8a9 SMP PREEMPT_DYNAMIC Thu J x86_64 x86_64 GNU/Linux

I can however reproduce this with on Compiler Explorer (see link below)

Code

Source

#include <stdio.h>

typedef void (Func)(void);
typedef struct { char *name; Func *ptr; } Function;

static void func_a(void) { printf("()"); }
static void func_b(void) { printf("()"); }
static void func_c(void) { printf("()"); }
static void func_d(void) { printf("()"); }

Function
    function_a = { "a", &func_a },
    function_b = { "b", &func_b },
    function_c = { "c", &func_c },
    function_d = { "d", &func_d };

Function *const functions[] = {
    &function_a,
    &function_b,
    &function_c,
    &function_d,
};

size_t functions_len = sizeof functions / sizeof *functions;

int main(void) {
    size_t i;

    setbuf(stdout, NULL);

    for (i = 0; i < functions_len; i++) {
        Function *const func = functions[i];
        printf("%s", func->name);
        func->ptr();
        printf(";");
    }

    return 0;
}

Disassembly

发布评论

评论列表(0)

  1. 暂无评论