https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111249
Bug ID: 111249 Summary: Aggressive loop optimization reports "iteration 2147483645 invokes undefined behavior" Product: gcc Version: 13.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: jonathan.leffler at gmail dot com Target Milestone: --- The problem occurs with GCC 12.2.0 and GCC 13.2.0. It is difficult to see how the loop could ever reach iteration 2147483645. It would have had undefined behaviour from iteration 3 onwards, anyway. Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/work1/gcc/v13.2.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/13.2.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../gcc-13.2.0/configure --prefix=/usr/gcc/v13.2.0 CC=/usr/gcc/v12.2.0/bin/gcc CXX=/usr/gcc/v12.2.0/bin/g++ Thread model: posix Supported LTO compression algorithms: zlib gcc version 13.2.0 (GCC) Command line: gcc -std=c99 -O3 -Wall -pedantic -Wold-style-definition -Wold-style-declaration -Wnested-externs -Wmissing-prototypes -Wextra -Werror -save-temps -c gcc-inline-bug.c Resulting errors: In function ‘sbt_subclass_put’: cc1: error: iteration 2147483645 invokes undefined behavior [-Werror=aggressive-loop-optimizations] In function ‘sbt_sendbuffer’, inlined from ‘sbt_subclass_put’ at gcc-inline-bug.c:95:15: gcc-inline-bug.c:52:23: note: within this loop 52 | for (int i = 0; i < n_info; i++) | ~~^~~~~~~~ cc1: all warnings being treated as errors Output file (gcc-inline-bug.i): # 0 "gcc-inline-bug.c" # 0 "<built-in>" # 0 "<command-line>" # 1 "/usr/include/stdc-predef.h" 1 3 4 # 0 "<command-line>" 2 # 1 "gcc-inline-bug.c" enum { E_Success = 0, E_Failure = -1 }; typedef long long LSN_t; typedef struct BUF_s BUF_t; typedef struct { LSN_t slri_lsn; BUF_t *slri_buf; } SLR_t; typedef struct SBT_s SBT_t; typedef struct { int (*sbtop_put)(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); } OPS_t; typedef struct { SLR_t *slri_info; } VAR_t; struct SBT_s { SBT_t *sbtv_next; LSN_t sbtv_last; OPS_t sbtv_ops; VAR_t sbtv_vars[24]; }; typedef struct { int sish_txid; } ISH_t; extern int sbt_subclass_put(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); extern int ISH_read(BUF_t *inbufp, ISH_t *in_header); extern int sbt_putbuf(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); extern int sbt_seterr(SBT_t *objp, int rc, int s); extern void slri_decref(BUF_t *slrip, const char *file, int line); extern void slri_set_empty(SLR_t *slrip); static int sbt_sendbuffer(SBT_t *objp, SLR_t **info, int n_info) { int rc = E_Success; for (int i = 0; i < n_info; i++) { SLR_t *pendp = info[i]; if (rc == E_Success) { int s = sbt_putbuf(objp->sbtv_next, pendp->slri_lsn, pendp->slri_buf); if (s == E_Success) objp->sbtv_last = pendp->slri_lsn; else rc = sbt_seterr(objp, s, 39); } slri_decref(pendp->slri_buf, "gcc-inline-bug.c", 68); slri_set_empty(pendp); } return rc; } int sbt_subclass_put(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf) { BUF_t *inbufp = a_buf; ISH_t in_header; int rc; if ((rc = ISH_read(inbufp, &in_header)) != E_Success) return E_Failure; VAR_t *vars = &objp->sbtv_vars[0]; SLR_t *pendp = &vars->slri_info[in_header.sish_txid]; ISH_t bef_header; if ((rc = ISH_read(pendp->slri_buf, &bef_header)) != E_Success) return E_Failure; SLR_t aft_bufinfo = { .slri_lsn = a_lsn, .slri_buf = inbufp }; SLR_t *tosend[2] = { pendp, &aft_bufinfo }; if ((rc = sbt_sendbuffer(objp, tosend, 2)) != E_Success) return E_Failure; return E_Success; } I was given a list of possible duplicates: 57199, 59651, 79517, 84867, 88272, 103724, and 106842. Of those, 103724 (closed because the GCC 10 code line is closed) and 106482 could be related, but neither deals with a function being inlined and then producing the warning. The others seem loosely related but not relevant. The original source code (gcc-inline-big.c) has some comments in it that the preprocessor removes: enum { E_Success = 0, E_Failure = -1 }; typedef long long LSN_t; typedef struct BUF_s BUF_t; typedef struct { LSN_t slri_lsn; BUF_t *slri_buf; } SLR_t; typedef struct SBT_s SBT_t; typedef struct { int (*sbtop_put)(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); } OPS_t; typedef struct { SLR_t *slri_info; } VAR_t; struct SBT_s { SBT_t *sbtv_next; LSN_t sbtv_last; OPS_t sbtv_ops; VAR_t sbtv_vars[24]; }; typedef struct { int sish_txid; } ISH_t; /* Entry point to module */ extern int sbt_subclass_put(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); /* Functions used by module */ extern int ISH_read(BUF_t *inbufp, ISH_t *in_header); extern int sbt_putbuf(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf); extern int sbt_seterr(SBT_t *objp, int rc, int s); extern void slri_decref(BUF_t *slrip, const char *file, int line); extern void slri_set_empty(SLR_t *slrip); static int sbt_sendbuffer(SBT_t *objp, SLR_t **info, int n_info) { int rc = E_Success; for (int i = 0; i < n_info; i++) { SLR_t *pendp = info[i]; if (rc == E_Success) { /* This call is part of the reproduction */ int s = sbt_putbuf(objp->sbtv_next, pendp->slri_lsn, pendp->slri_buf); if (s == E_Success) objp->sbtv_last = pendp->slri_lsn; else /* Change this to rc = E_Failure; and the bug goes away */ rc = sbt_seterr(objp, s, 39); } /* These lines are part of the reproduction - delete either and the bug goes away */ slri_decref(pendp->slri_buf, __FILE__, __LINE__); slri_set_empty(pendp); } return rc; } int sbt_subclass_put(SBT_t *objp, LSN_t a_lsn, BUF_t *a_buf) { BUF_t *inbufp = a_buf; ISH_t in_header; int rc; if ((rc = ISH_read(inbufp, &in_header)) != E_Success) return E_Failure; VAR_t *vars = &objp->sbtv_vars[0]; SLR_t *pendp = &vars->slri_info[in_header.sish_txid]; ISH_t bef_header; if ((rc = ISH_read(pendp->slri_buf, &bef_header)) != E_Success) return E_Failure; SLR_t aft_bufinfo = { .slri_lsn = a_lsn, .slri_buf = inbufp }; SLR_t *tosend[2] = { pendp, &aft_bufinfo }; if ((rc = sbt_sendbuffer(objp, tosend, 2)) != E_Success) return E_Failure; return E_Success; }