首页 > 解决方案 > 链接器抱怨可能未初始化的变量(完全优化的构建选项)

问题描述

我正在编译一些以前编译过的代码(使用相同的选项),并且在一些不相关的更改之后,链接器开始查找可能未初始化的变量(我怀疑这些不相关的更改可能会干扰 gcc 的优化算法并可能触发错误) .

系统:

我使用以下优化:

-O3 -flto -fuse-linker-plugin -march=native -static

该程序试图建立一个 tcp 服务器,而套接字可能是未初始化的变量。

libalx/base/socket/tcp/server.c

#include "libalx/base/socket/tcp/server.h"

#include <errno.h>
#include <stddef.h>
#include <stdlib.h>

#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>


static
int     get_addrs       (const char *server_port, struct addrinfo **addrs);
static
int     set_server      (int sd, int *optval, struct addrinfo *ad, int backlog);
static
int     set_socket      (struct addrinfo *addrs, int backlog);


int     tcp_server_open     (const char *server_port, int backlog)
{
        int             sd;
        struct addrinfo *addrs;

        sd      = -1;
        if (get_addrs(server_port, &addrs))
                return  -1;
        sd      = set_socket(addrs, backlog);
        freeaddrinfo(addrs);

        if (sd < 0)
                return  -2;
        return  sd;
}


static
int     get_addrs       (const char *server_port, struct addrinfo **addrs)
{
        struct protoent *tcp;
        struct addrinfo hint = {0};

        tcp     = getprotobyname("tcp");
        if (!tcp)
                return  -1;
        hint.ai_family          = AF_UNSPEC;
        hint.ai_socktype        = SOCK_STREAM;
        hint.ai_protocol        = tcp->p_proto;
        hint.ai_flags           = AI_PASSIVE;
        if (getaddrinfo(NULL, server_port, &hint, addrs))
                return  -1;
        return  0;
}

static
int     set_socket      (struct addrinfo *addrs, int backlog)
{
        int     val;
        int     sock;

        sock    = -1;
        for (struct addrinfo *ad = addrs; ad; ad = ad->ai_next) {
                sock = socket(ad->ai_family, ad->ai_socktype, ad->ai_protocol);
                if (sock < 0)
                        continue;
                if (!set_server(sock, &val, ad, backlog))
                        break;
                close(sock);
                sock    = -1;
        }

        return  sock;
}

static
int     set_server      (int sd, int *optval, struct addrinfo *ad, int backlog)
{

        *optval = 1;
        if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, optval, sizeof(*optval)))
                return  -1;
        if (bind(sd, ad->ai_addr, ad->ai_addrlen))
                return  -1;
        if (listen(sd, backlog))
                return  -1;
        return  0;
}

libalx/base/linux/membarrier.h

#include <unistd.h>
#include <sys/syscall.h>


inline
int membarrier  (int cmd, int flags)
{
    return  syscall(__NR_membarrier, cmd, flags);
}

main.c

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <sys/socket.h>
#include <unistd.h>

#include <linux/membarrier.h>

#define ALX_NO_PREFIX
#include <libalx/base/compiler/size.h>
#include <libalx/base/linux/membarrier.h>
#include <libalx/base/socket/tcp/server.h>


static  int             mb_cmd;
static  sig_atomic_t    sigterm;
static  int             tcp;


static
int     rob_init        (void);
static
int     rob_deinit      (void);
static
int     tcp_init        (void);
static
int     tcp_deinit      (void);

static
void    cam_session     (int cam);

static
int     mb_init         (void);
static
int     sigterm_init    (void);
static
void    sigterm_handler (int sig);


int     main            (void)
{
        int                     tcp;
        int                     cam;
        struct sockaddr_storage cam_addr = {0};
        socklen_t               cam_addr_len;
        int                     status;

        status  = 1;
        if (rob_init())
                goto out0;

        status++;
        cam_addr_len    = sizeof(cam_addr);
        do {
                cam = accept(tcp, (struct sockaddr *)&cam_addr, &cam_addr_len);
                if (cam < 0) {
                        goto retry;
                }

                cam_session(cam);
                close(cam);
        retry:
                asm volatile ("" : : : "memory");
        } while (!sigterm);

        status  = EXIT_SUCCESS;

        if (rob_deinit())
                status  += 32;
out0:
        fprintf(stderr, "rob: ERROR: main(): %i\n", status);

        return  status;
}


static
int     rob_init        (void)
{
        int     status;

        status  = -1;
        if (sigterm_init())
                goto err;
        status--;
        if (tcp_init())
                goto err;
        return  0;
err:
        fprintf(stderr, "rob: ERROR: rob_init(): %i\n", status);
        return  status;
}

static
int     rob_deinit      (void)
{
        int     status;

        status  = 0;
        if (tcp_deinit())
                status--;

        return  status;
}

static
int     tcp_init        (void)
{

        tcp     = -1;
        tcp     = tcp_server_open("23", 10);
        return  tcp < 0;
}

static
int     tcp_deinit      (void)
{
        return  close(tcp);
}

static
void    cam_session     (int cam)
{
        static  int i = 0;
        char    cam_data[BUFSIZ];
        ssize_t n;

        i++;
        while (true) {
                n = read(cam, cam_data, ARRAY_SIZE(cam_data) - 1);
                if (n < 0)
                        return;
                cam_data[n]     = 0;
                if (!n)
                        return;
                printf("%s\n", cam_data);
        }
}


static
int     mb_init         (void)
{
        static bool     done = false;
        int             cmd;

        if (done)
                return  0;

        cmd     = membarrier(MEMBARRIER_CMD_QUERY, 0);
        if (cmd < 0)
                return  -2;

        if (cmd & MEMBARRIER_CMD_PRIVATE_EXPEDITED) {
                mb_cmd  = MEMBARRIER_CMD_PRIVATE_EXPEDITED;
                if (membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0))
                        return  -3;
        } else if (cmd & MEMBARRIER_CMD_GLOBAL_EXPEDITED) {
                mb_cmd  = MEMBARRIER_CMD_GLOBAL_EXPEDITED;
                if (membarrier(MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, 0))
                        return  -4;
        } else {
                mb_cmd  = MEMBARRIER_CMD_GLOBAL;
        }

        done    = true;
        return  membarrier(mb_cmd, 0);
}

static
int     sigterm_init    (void)
{
        struct sigaction        sa = {0};

        if (mb_init())
                return  -1;

        sigterm = false;
        membarrier(mb_cmd, 0);

        sigemptyset(&sa.sa_mask);
        sa.sa_handler   = &sigterm_handler;
        if (sigaction(SIGTERM, &sa, NULL))
                return  -3;
        return  0;
}

static
void    sigterm_handler (int sig)
{

        (void)sig;

        sigterm = true;
        membarrier(mb_cmd, 0);
}

我尝试跟踪未初始化变量的来源,但没有发现任何 100% 清楚的东西。我的代码中是否缺少某些路径,或者可能存在一些错误路径socket()socket()是我无法控制的唯一来源,并且可能将其设置为未初始化。

错误:

$ make
gcc -Wall -Wextra -Werror -Wno-implicit-fallthrough -O3 -march=native -flto -fuse-linker-plugin -static `pkg-config --static --cflags libalx-base libalx-telnet-tcp` \
        rob.c -o rob                    \
        `pkg-config --static --libs libalx-telnet-tcp libalx-base`
rob.c: In function ‘main’:
rob.c:66:9: error: ‘tcp’ may be used uninitialized in this function [-Werror=maybe-uninitialized]
   66 |   cam = accept(tcp, (struct sockaddr *)&cam_addr, &cam_addr_len);
      |         ^
rob.c:53:8: note: ‘tcp’ was declared here
   53 |  int   tcp;
      |        ^
lto1: all warnings being treated as errors
lto-wrapper: fatal error: gcc returned 1 exit status
compilation terminated.
/usr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
make: *** [Makefile:9: rob] Error 1

标签: clinuxsocketsgcclto

解决方案


推荐阅读