Skip to content

build: --enable-debug compiles at -O2 instead of -O0 (regression since 2018) #4789

Description

@ThalesBarretto

Summary

./configure --enable-debug is meant to produce an unoptimized, debuggable build: its own
code sets -g -O0 -DDEBUG. The resulting build is in fact compiled at -O2. -g and
-DDEBUG take effect, but the -O0 is silently overridden, so a "debug" build is as hard to
step through in gdb as a release build (inlined frames, "value optimized out"). This has been
the case since b91325caa3 (2018-12-28) and also affects rpmbuild --with debug.

Observed on devel @ a482a8578a; reproduced on 14 distro toolchains (details below).

Root cause

--enable-debug puts -O0 into GF_CFLAGS, which reaches the compiler through
AM_CFLAGS / the per-target _CFLAGS. automake emits every compile as
… $(AM_CFLAGS) $(CFLAGS) …, so CFLAGS is placed last. autoconf's AC_PROG_CC
defaults CFLAGS to -g -O2 for gcc (and the RPM %configure macro exports
CFLAGS=%{optflags}, i.e. -O2 …), and configure.ac never neutralizes that. gcc honours
the last -O on the command line, so the -O2 from CFLAGS wins over the -O0
from GF_CFLAGS.

Real compile line for one TU under ./configure --enable-debug (make V=1):

gcc … -g -O0 -DDEBUG …(from GF_CFLAGS)… -g -O2 -fsigned-char …(from CFLAGS)… -c mem-pool.c
        └─ intended                                └─ wins (last -O)

Decisive check (gcc defines __OPTIMIZE__ iff the effective level is ≥ -O1):

gcc -O0 -DDEBUG -O2 …  → __OPTIMIZE__ defined    (effective -O2)
gcc -O0            …  → __OPTIMIZE__ undefined  (effective -O0)

History: this used to work

  • 2012, d9ddb5fb95 — --enable-debug introduced; put the level in CFLAGS
    (CFLAGS="-O0 $CFLAGS"), emitted last, so -O0 won.
  • 2013, d85e394847 (RHBZ 955283, "enable-debug change breaks _hardened_build") — kept
    -O0 in CFLAGS via a surgical sed -e s/O2/O0/, so distro hardening flags survived.
  • 2018, b91325caa3 ("configure: fix the duplicate CFLAGS options") — moved -g -O0 -DDEBUG
    from CFLAGS to GF_CFLAGS while removing genuine flag duplication elsewhere. That demoted
    the -O0 below CFLAGS. Building the same ./configure --enable-debug on that commit and
    on its parent shows the flip: parent → effective -O0, commit → effective -O2.

Why CI and the in-tree helpers did not catch it

The automated consumers of --enable-debug never see autoconf's -O2:

  • upstream Jenkins regression CI (build.sh in the separate gluster/glusterfs-patch-acceptance-tests
    repository) configures with --enable-debug and then runs make install CFLAGS="-Wall -Werror -Wno-cpp". That make-line
    override replaces configure's entire CFLAGS, so the -O2 is gone and the -O0 carried by
    GF_CFLAGS is the only optimisation token. CI has therefore been building at -O0 all along.
  • the in-tree helpers (run-tests-in-vagrant.sh, extras/devel-tools/devel-vagrant,
    extras/distributed-testing) pass an explicit CFLAGS="-g -O0 …" next to --enable-debug.

Only a plain ./configure --enable-debug (what a developer types) and rpmbuild --with debug
(where %configure exports CFLAGS=%optflags) hit it, and in both cases the build still
succeeds, just optimized, so nothing fails loudly.

Impact

  • Developer debug builds are optimized: gdb shows inlined frames and <optimized out> variables.
  • rpmbuild --with debug produces optimized "debug" RPMs.
  • -DDEBUG instrumentation (mem-pool accounting etc.) and -g are unaffected.
  • No distro's default packaging passes --enable-debug, so no shipped release binary is
    affected either way.

Fix

Keep -g -DDEBUG in GF_CFLAGS and append -O0 to CFLAGS, so it lands last and wins,
without clobbering anything already in CFLAGS (distro hardening flags stay intact — the
mistake behind RHBZ 955283 was clobbering CFLAGS, and appending avoids it; it is also robust
to -O3/-Os/-Og/no -O, unlike the 2013 sed). A PR with the one-hunk change follows.

Verification of the fix

  • Arch Linux (2026-09; gcc 16.2.1, glibc 2.44, autoconf 2.73): --enable-debug → effective
    -O0, both plain and with Fedora 42 %optflags as CFLAGS (-fstack-protector-strong,
    -D_FORTIFY_SOURCE=3, -fcf-protection, -fstack-clash-protection all still on the line);
    full tree builds with 0 errors in three allocator/io configurations.
  • AlmaLinux 8.10 (gcc 8.5): real rpmbuild -tb --with debug before/after — before, all 351
    translation units end with -O2; after, all 351 end with -O0; both builds succeed and
    produce the same 39 packages; EL8 hardening flags intact.
  • 14 distro containers (AlmaLinux 8, CentOS Stream 9, Fedora 42, Leap 15.6, Tumbleweed, Arch,
    Debian 12, Debian 13 amd64, Ubuntu 20.04/22.04/24.04, plus Debian 13 i386, Alpine 3.22 and
    Alpine edge as compile-line-only oracles;
    autoconf 2.69–2.73, gcc 7.5–16.2, glibc 2.28–2.44 and musl), each with its own autotools:
    identical flip on every one, same make result / error set / object counts before and after,
    and the generated build system differs only in the CFLAGS/GF_CFLAGS lines.
  • CI shape (make CFLAGS="-Wall -Werror -Wno-cpp" after --enable-debug): stays at -O0
    (the line then carries no -O token, which gcc treats as -O0).

One expected side effect of any real -O0 build: where CFLAGS carries -D_FORTIFY_SOURCE,
glibc's features.h emits #warning _FORTIFY_SOURCE requires compiling with optimization (-O)
once per TU (Fedora/EL/SUSE/Arch glibc; Debian/Ubuntu glibc carries no such warning). That was
also the state of --enable-debug from 2013 to 2018.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions