diff options
author | Martin Liska <mliska@suse.cz> | 2022-01-14 16:56:44 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-01-17 22:12:04 +0100 |
commit | 5c69acb32329d49e58c26fa41ae74229a52b9106 (patch) | |
tree | ddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/gimple-ssa-sprintf.c | |
parent | 490e23032baaece71f2ec09fa1805064b150fbc2 (diff) | |
download | gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2 |
Rename .c files to .cc files.
gcc/ada/ChangeLog:
* adadecode.c: Moved to...
* adadecode.cc: ...here.
* affinity.c: Moved to...
* affinity.cc: ...here.
* argv-lynxos178-raven-cert.c: Moved to...
* argv-lynxos178-raven-cert.cc: ...here.
* argv.c: Moved to...
* argv.cc: ...here.
* aux-io.c: Moved to...
* aux-io.cc: ...here.
* cio.c: Moved to...
* cio.cc: ...here.
* cstreams.c: Moved to...
* cstreams.cc: ...here.
* env.c: Moved to...
* env.cc: ...here.
* exit.c: Moved to...
* exit.cc: ...here.
* expect.c: Moved to...
* expect.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* gcc-interface/cuintp.c: Moved to...
* gcc-interface/cuintp.cc: ...here.
* gcc-interface/decl.c: Moved to...
* gcc-interface/decl.cc: ...here.
* gcc-interface/misc.c: Moved to...
* gcc-interface/misc.cc: ...here.
* gcc-interface/targtyps.c: Moved to...
* gcc-interface/targtyps.cc: ...here.
* gcc-interface/trans.c: Moved to...
* gcc-interface/trans.cc: ...here.
* gcc-interface/utils.c: Moved to...
* gcc-interface/utils.cc: ...here.
* gcc-interface/utils2.c: Moved to...
* gcc-interface/utils2.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* initialize.c: Moved to...
* initialize.cc: ...here.
* libgnarl/thread.c: Moved to...
* libgnarl/thread.cc: ...here.
* link.c: Moved to...
* link.cc: ...here.
* locales.c: Moved to...
* locales.cc: ...here.
* mkdir.c: Moved to...
* mkdir.cc: ...here.
* raise.c: Moved to...
* raise.cc: ...here.
* rtfinal.c: Moved to...
* rtfinal.cc: ...here.
* rtinit.c: Moved to...
* rtinit.cc: ...here.
* seh_init.c: Moved to...
* seh_init.cc: ...here.
* sigtramp-armdroid.c: Moved to...
* sigtramp-armdroid.cc: ...here.
* sigtramp-ios.c: Moved to...
* sigtramp-ios.cc: ...here.
* sigtramp-qnx.c: Moved to...
* sigtramp-qnx.cc: ...here.
* sigtramp-vxworks.c: Moved to...
* sigtramp-vxworks.cc: ...here.
* socket.c: Moved to...
* socket.cc: ...here.
* tracebak.c: Moved to...
* tracebak.cc: ...here.
* version.c: Moved to...
* version.cc: ...here.
* vx_stack_info.c: Moved to...
* vx_stack_info.cc: ...here.
gcc/ChangeLog:
* adjust-alignment.c: Moved to...
* adjust-alignment.cc: ...here.
* alias.c: Moved to...
* alias.cc: ...here.
* alloc-pool.c: Moved to...
* alloc-pool.cc: ...here.
* asan.c: Moved to...
* asan.cc: ...here.
* attribs.c: Moved to...
* attribs.cc: ...here.
* auto-inc-dec.c: Moved to...
* auto-inc-dec.cc: ...here.
* auto-profile.c: Moved to...
* auto-profile.cc: ...here.
* bb-reorder.c: Moved to...
* bb-reorder.cc: ...here.
* bitmap.c: Moved to...
* bitmap.cc: ...here.
* btfout.c: Moved to...
* btfout.cc: ...here.
* builtins.c: Moved to...
* builtins.cc: ...here.
* caller-save.c: Moved to...
* caller-save.cc: ...here.
* calls.c: Moved to...
* calls.cc: ...here.
* ccmp.c: Moved to...
* ccmp.cc: ...here.
* cfg.c: Moved to...
* cfg.cc: ...here.
* cfganal.c: Moved to...
* cfganal.cc: ...here.
* cfgbuild.c: Moved to...
* cfgbuild.cc: ...here.
* cfgcleanup.c: Moved to...
* cfgcleanup.cc: ...here.
* cfgexpand.c: Moved to...
* cfgexpand.cc: ...here.
* cfghooks.c: Moved to...
* cfghooks.cc: ...here.
* cfgloop.c: Moved to...
* cfgloop.cc: ...here.
* cfgloopanal.c: Moved to...
* cfgloopanal.cc: ...here.
* cfgloopmanip.c: Moved to...
* cfgloopmanip.cc: ...here.
* cfgrtl.c: Moved to...
* cfgrtl.cc: ...here.
* cgraph.c: Moved to...
* cgraph.cc: ...here.
* cgraphbuild.c: Moved to...
* cgraphbuild.cc: ...here.
* cgraphclones.c: Moved to...
* cgraphclones.cc: ...here.
* cgraphunit.c: Moved to...
* cgraphunit.cc: ...here.
* collect-utils.c: Moved to...
* collect-utils.cc: ...here.
* collect2-aix.c: Moved to...
* collect2-aix.cc: ...here.
* collect2.c: Moved to...
* collect2.cc: ...here.
* combine-stack-adj.c: Moved to...
* combine-stack-adj.cc: ...here.
* combine.c: Moved to...
* combine.cc: ...here.
* common/common-targhooks.c: Moved to...
* common/common-targhooks.cc: ...here.
* common/config/aarch64/aarch64-common.c: Moved to...
* common/config/aarch64/aarch64-common.cc: ...here.
* common/config/alpha/alpha-common.c: Moved to...
* common/config/alpha/alpha-common.cc: ...here.
* common/config/arc/arc-common.c: Moved to...
* common/config/arc/arc-common.cc: ...here.
* common/config/arm/arm-common.c: Moved to...
* common/config/arm/arm-common.cc: ...here.
* common/config/avr/avr-common.c: Moved to...
* common/config/avr/avr-common.cc: ...here.
* common/config/bfin/bfin-common.c: Moved to...
* common/config/bfin/bfin-common.cc: ...here.
* common/config/bpf/bpf-common.c: Moved to...
* common/config/bpf/bpf-common.cc: ...here.
* common/config/c6x/c6x-common.c: Moved to...
* common/config/c6x/c6x-common.cc: ...here.
* common/config/cr16/cr16-common.c: Moved to...
* common/config/cr16/cr16-common.cc: ...here.
* common/config/cris/cris-common.c: Moved to...
* common/config/cris/cris-common.cc: ...here.
* common/config/csky/csky-common.c: Moved to...
* common/config/csky/csky-common.cc: ...here.
* common/config/default-common.c: Moved to...
* common/config/default-common.cc: ...here.
* common/config/epiphany/epiphany-common.c: Moved to...
* common/config/epiphany/epiphany-common.cc: ...here.
* common/config/fr30/fr30-common.c: Moved to...
* common/config/fr30/fr30-common.cc: ...here.
* common/config/frv/frv-common.c: Moved to...
* common/config/frv/frv-common.cc: ...here.
* common/config/gcn/gcn-common.c: Moved to...
* common/config/gcn/gcn-common.cc: ...here.
* common/config/h8300/h8300-common.c: Moved to...
* common/config/h8300/h8300-common.cc: ...here.
* common/config/i386/i386-common.c: Moved to...
* common/config/i386/i386-common.cc: ...here.
* common/config/ia64/ia64-common.c: Moved to...
* common/config/ia64/ia64-common.cc: ...here.
* common/config/iq2000/iq2000-common.c: Moved to...
* common/config/iq2000/iq2000-common.cc: ...here.
* common/config/lm32/lm32-common.c: Moved to...
* common/config/lm32/lm32-common.cc: ...here.
* common/config/m32r/m32r-common.c: Moved to...
* common/config/m32r/m32r-common.cc: ...here.
* common/config/m68k/m68k-common.c: Moved to...
* common/config/m68k/m68k-common.cc: ...here.
* common/config/mcore/mcore-common.c: Moved to...
* common/config/mcore/mcore-common.cc: ...here.
* common/config/microblaze/microblaze-common.c: Moved to...
* common/config/microblaze/microblaze-common.cc: ...here.
* common/config/mips/mips-common.c: Moved to...
* common/config/mips/mips-common.cc: ...here.
* common/config/mmix/mmix-common.c: Moved to...
* common/config/mmix/mmix-common.cc: ...here.
* common/config/mn10300/mn10300-common.c: Moved to...
* common/config/mn10300/mn10300-common.cc: ...here.
* common/config/msp430/msp430-common.c: Moved to...
* common/config/msp430/msp430-common.cc: ...here.
* common/config/nds32/nds32-common.c: Moved to...
* common/config/nds32/nds32-common.cc: ...here.
* common/config/nios2/nios2-common.c: Moved to...
* common/config/nios2/nios2-common.cc: ...here.
* common/config/nvptx/nvptx-common.c: Moved to...
* common/config/nvptx/nvptx-common.cc: ...here.
* common/config/or1k/or1k-common.c: Moved to...
* common/config/or1k/or1k-common.cc: ...here.
* common/config/pa/pa-common.c: Moved to...
* common/config/pa/pa-common.cc: ...here.
* common/config/pdp11/pdp11-common.c: Moved to...
* common/config/pdp11/pdp11-common.cc: ...here.
* common/config/pru/pru-common.c: Moved to...
* common/config/pru/pru-common.cc: ...here.
* common/config/riscv/riscv-common.c: Moved to...
* common/config/riscv/riscv-common.cc: ...here.
* common/config/rs6000/rs6000-common.c: Moved to...
* common/config/rs6000/rs6000-common.cc: ...here.
* common/config/rx/rx-common.c: Moved to...
* common/config/rx/rx-common.cc: ...here.
* common/config/s390/s390-common.c: Moved to...
* common/config/s390/s390-common.cc: ...here.
* common/config/sh/sh-common.c: Moved to...
* common/config/sh/sh-common.cc: ...here.
* common/config/sparc/sparc-common.c: Moved to...
* common/config/sparc/sparc-common.cc: ...here.
* common/config/tilegx/tilegx-common.c: Moved to...
* common/config/tilegx/tilegx-common.cc: ...here.
* common/config/tilepro/tilepro-common.c: Moved to...
* common/config/tilepro/tilepro-common.cc: ...here.
* common/config/v850/v850-common.c: Moved to...
* common/config/v850/v850-common.cc: ...here.
* common/config/vax/vax-common.c: Moved to...
* common/config/vax/vax-common.cc: ...here.
* common/config/visium/visium-common.c: Moved to...
* common/config/visium/visium-common.cc: ...here.
* common/config/xstormy16/xstormy16-common.c: Moved to...
* common/config/xstormy16/xstormy16-common.cc: ...here.
* common/config/xtensa/xtensa-common.c: Moved to...
* common/config/xtensa/xtensa-common.cc: ...here.
* compare-elim.c: Moved to...
* compare-elim.cc: ...here.
* config/aarch64/aarch64-bti-insert.c: Moved to...
* config/aarch64/aarch64-bti-insert.cc: ...here.
* config/aarch64/aarch64-builtins.c: Moved to...
* config/aarch64/aarch64-builtins.cc: ...here.
* config/aarch64/aarch64-c.c: Moved to...
* config/aarch64/aarch64-c.cc: ...here.
* config/aarch64/aarch64-d.c: Moved to...
* config/aarch64/aarch64-d.cc: ...here.
* config/aarch64/aarch64.c: Moved to...
* config/aarch64/aarch64.cc: ...here.
* config/aarch64/cortex-a57-fma-steering.c: Moved to...
* config/aarch64/cortex-a57-fma-steering.cc: ...here.
* config/aarch64/driver-aarch64.c: Moved to...
* config/aarch64/driver-aarch64.cc: ...here.
* config/aarch64/falkor-tag-collision-avoidance.c: Moved to...
* config/aarch64/falkor-tag-collision-avoidance.cc: ...here.
* config/aarch64/host-aarch64-darwin.c: Moved to...
* config/aarch64/host-aarch64-darwin.cc: ...here.
* config/alpha/alpha.c: Moved to...
* config/alpha/alpha.cc: ...here.
* config/alpha/driver-alpha.c: Moved to...
* config/alpha/driver-alpha.cc: ...here.
* config/arc/arc-c.c: Moved to...
* config/arc/arc-c.cc: ...here.
* config/arc/arc.c: Moved to...
* config/arc/arc.cc: ...here.
* config/arc/driver-arc.c: Moved to...
* config/arc/driver-arc.cc: ...here.
* config/arm/aarch-common.c: Moved to...
* config/arm/aarch-common.cc: ...here.
* config/arm/arm-builtins.c: Moved to...
* config/arm/arm-builtins.cc: ...here.
* config/arm/arm-c.c: Moved to...
* config/arm/arm-c.cc: ...here.
* config/arm/arm-d.c: Moved to...
* config/arm/arm-d.cc: ...here.
* config/arm/arm.c: Moved to...
* config/arm/arm.cc: ...here.
* config/arm/driver-arm.c: Moved to...
* config/arm/driver-arm.cc: ...here.
* config/avr/avr-c.c: Moved to...
* config/avr/avr-c.cc: ...here.
* config/avr/avr-devices.c: Moved to...
* config/avr/avr-devices.cc: ...here.
* config/avr/avr-log.c: Moved to...
* config/avr/avr-log.cc: ...here.
* config/avr/avr.c: Moved to...
* config/avr/avr.cc: ...here.
* config/avr/driver-avr.c: Moved to...
* config/avr/driver-avr.cc: ...here.
* config/avr/gen-avr-mmcu-specs.c: Moved to...
* config/avr/gen-avr-mmcu-specs.cc: ...here.
* config/avr/gen-avr-mmcu-texi.c: Moved to...
* config/avr/gen-avr-mmcu-texi.cc: ...here.
* config/bfin/bfin.c: Moved to...
* config/bfin/bfin.cc: ...here.
* config/bpf/bpf.c: Moved to...
* config/bpf/bpf.cc: ...here.
* config/bpf/coreout.c: Moved to...
* config/bpf/coreout.cc: ...here.
* config/c6x/c6x.c: Moved to...
* config/c6x/c6x.cc: ...here.
* config/cr16/cr16.c: Moved to...
* config/cr16/cr16.cc: ...here.
* config/cris/cris.c: Moved to...
* config/cris/cris.cc: ...here.
* config/csky/csky.c: Moved to...
* config/csky/csky.cc: ...here.
* config/darwin-c.c: Moved to...
* config/darwin-c.cc: ...here.
* config/darwin-d.c: Moved to...
* config/darwin-d.cc: ...here.
* config/darwin-driver.c: Moved to...
* config/darwin-driver.cc: ...here.
* config/darwin-f.c: Moved to...
* config/darwin-f.cc: ...here.
* config/darwin.c: Moved to...
* config/darwin.cc: ...here.
* config/default-c.c: Moved to...
* config/default-c.cc: ...here.
* config/default-d.c: Moved to...
* config/default-d.cc: ...here.
* config/dragonfly-d.c: Moved to...
* config/dragonfly-d.cc: ...here.
* config/epiphany/epiphany.c: Moved to...
* config/epiphany/epiphany.cc: ...here.
* config/epiphany/mode-switch-use.c: Moved to...
* config/epiphany/mode-switch-use.cc: ...here.
* config/epiphany/resolve-sw-modes.c: Moved to...
* config/epiphany/resolve-sw-modes.cc: ...here.
* config/fr30/fr30.c: Moved to...
* config/fr30/fr30.cc: ...here.
* config/freebsd-d.c: Moved to...
* config/freebsd-d.cc: ...here.
* config/frv/frv.c: Moved to...
* config/frv/frv.cc: ...here.
* config/ft32/ft32.c: Moved to...
* config/ft32/ft32.cc: ...here.
* config/gcn/driver-gcn.c: Moved to...
* config/gcn/driver-gcn.cc: ...here.
* config/gcn/gcn-run.c: Moved to...
* config/gcn/gcn-run.cc: ...here.
* config/gcn/gcn-tree.c: Moved to...
* config/gcn/gcn-tree.cc: ...here.
* config/gcn/gcn.c: Moved to...
* config/gcn/gcn.cc: ...here.
* config/gcn/mkoffload.c: Moved to...
* config/gcn/mkoffload.cc: ...here.
* config/glibc-c.c: Moved to...
* config/glibc-c.cc: ...here.
* config/glibc-d.c: Moved to...
* config/glibc-d.cc: ...here.
* config/h8300/h8300.c: Moved to...
* config/h8300/h8300.cc: ...here.
* config/host-darwin.c: Moved to...
* config/host-darwin.cc: ...here.
* config/host-hpux.c: Moved to...
* config/host-hpux.cc: ...here.
* config/host-linux.c: Moved to...
* config/host-linux.cc: ...here.
* config/host-netbsd.c: Moved to...
* config/host-netbsd.cc: ...here.
* config/host-openbsd.c: Moved to...
* config/host-openbsd.cc: ...here.
* config/host-solaris.c: Moved to...
* config/host-solaris.cc: ...here.
* config/i386/djgpp.c: Moved to...
* config/i386/djgpp.cc: ...here.
* config/i386/driver-i386.c: Moved to...
* config/i386/driver-i386.cc: ...here.
* config/i386/driver-mingw32.c: Moved to...
* config/i386/driver-mingw32.cc: ...here.
* config/i386/gnu-property.c: Moved to...
* config/i386/gnu-property.cc: ...here.
* config/i386/host-cygwin.c: Moved to...
* config/i386/host-cygwin.cc: ...here.
* config/i386/host-i386-darwin.c: Moved to...
* config/i386/host-i386-darwin.cc: ...here.
* config/i386/host-mingw32.c: Moved to...
* config/i386/host-mingw32.cc: ...here.
* config/i386/i386-builtins.c: Moved to...
* config/i386/i386-builtins.cc: ...here.
* config/i386/i386-c.c: Moved to...
* config/i386/i386-c.cc: ...here.
* config/i386/i386-d.c: Moved to...
* config/i386/i386-d.cc: ...here.
* config/i386/i386-expand.c: Moved to...
* config/i386/i386-expand.cc: ...here.
* config/i386/i386-features.c: Moved to...
* config/i386/i386-features.cc: ...here.
* config/i386/i386-options.c: Moved to...
* config/i386/i386-options.cc: ...here.
* config/i386/i386.c: Moved to...
* config/i386/i386.cc: ...here.
* config/i386/intelmic-mkoffload.c: Moved to...
* config/i386/intelmic-mkoffload.cc: ...here.
* config/i386/msformat-c.c: Moved to...
* config/i386/msformat-c.cc: ...here.
* config/i386/winnt-cxx.c: Moved to...
* config/i386/winnt-cxx.cc: ...here.
* config/i386/winnt-d.c: Moved to...
* config/i386/winnt-d.cc: ...here.
* config/i386/winnt-stubs.c: Moved to...
* config/i386/winnt-stubs.cc: ...here.
* config/i386/winnt.c: Moved to...
* config/i386/winnt.cc: ...here.
* config/i386/x86-tune-sched-atom.c: Moved to...
* config/i386/x86-tune-sched-atom.cc: ...here.
* config/i386/x86-tune-sched-bd.c: Moved to...
* config/i386/x86-tune-sched-bd.cc: ...here.
* config/i386/x86-tune-sched-core.c: Moved to...
* config/i386/x86-tune-sched-core.cc: ...here.
* config/i386/x86-tune-sched.c: Moved to...
* config/i386/x86-tune-sched.cc: ...here.
* config/ia64/ia64-c.c: Moved to...
* config/ia64/ia64-c.cc: ...here.
* config/ia64/ia64.c: Moved to...
* config/ia64/ia64.cc: ...here.
* config/iq2000/iq2000.c: Moved to...
* config/iq2000/iq2000.cc: ...here.
* config/linux.c: Moved to...
* config/linux.cc: ...here.
* config/lm32/lm32.c: Moved to...
* config/lm32/lm32.cc: ...here.
* config/m32c/m32c-pragma.c: Moved to...
* config/m32c/m32c-pragma.cc: ...here.
* config/m32c/m32c.c: Moved to...
* config/m32c/m32c.cc: ...here.
* config/m32r/m32r.c: Moved to...
* config/m32r/m32r.cc: ...here.
* config/m68k/m68k.c: Moved to...
* config/m68k/m68k.cc: ...here.
* config/mcore/mcore.c: Moved to...
* config/mcore/mcore.cc: ...here.
* config/microblaze/microblaze-c.c: Moved to...
* config/microblaze/microblaze-c.cc: ...here.
* config/microblaze/microblaze.c: Moved to...
* config/microblaze/microblaze.cc: ...here.
* config/mips/driver-native.c: Moved to...
* config/mips/driver-native.cc: ...here.
* config/mips/frame-header-opt.c: Moved to...
* config/mips/frame-header-opt.cc: ...here.
* config/mips/mips-d.c: Moved to...
* config/mips/mips-d.cc: ...here.
* config/mips/mips.c: Moved to...
* config/mips/mips.cc: ...here.
* config/mmix/mmix.c: Moved to...
* config/mmix/mmix.cc: ...here.
* config/mn10300/mn10300.c: Moved to...
* config/mn10300/mn10300.cc: ...here.
* config/moxie/moxie.c: Moved to...
* config/moxie/moxie.cc: ...here.
* config/msp430/driver-msp430.c: Moved to...
* config/msp430/driver-msp430.cc: ...here.
* config/msp430/msp430-c.c: Moved to...
* config/msp430/msp430-c.cc: ...here.
* config/msp430/msp430-devices.c: Moved to...
* config/msp430/msp430-devices.cc: ...here.
* config/msp430/msp430.c: Moved to...
* config/msp430/msp430.cc: ...here.
* config/nds32/nds32-cost.c: Moved to...
* config/nds32/nds32-cost.cc: ...here.
* config/nds32/nds32-fp-as-gp.c: Moved to...
* config/nds32/nds32-fp-as-gp.cc: ...here.
* config/nds32/nds32-intrinsic.c: Moved to...
* config/nds32/nds32-intrinsic.cc: ...here.
* config/nds32/nds32-isr.c: Moved to...
* config/nds32/nds32-isr.cc: ...here.
* config/nds32/nds32-md-auxiliary.c: Moved to...
* config/nds32/nds32-md-auxiliary.cc: ...here.
* config/nds32/nds32-memory-manipulation.c: Moved to...
* config/nds32/nds32-memory-manipulation.cc: ...here.
* config/nds32/nds32-pipelines-auxiliary.c: Moved to...
* config/nds32/nds32-pipelines-auxiliary.cc: ...here.
* config/nds32/nds32-predicates.c: Moved to...
* config/nds32/nds32-predicates.cc: ...here.
* config/nds32/nds32-relax-opt.c: Moved to...
* config/nds32/nds32-relax-opt.cc: ...here.
* config/nds32/nds32-utils.c: Moved to...
* config/nds32/nds32-utils.cc: ...here.
* config/nds32/nds32.c: Moved to...
* config/nds32/nds32.cc: ...here.
* config/netbsd-d.c: Moved to...
* config/netbsd-d.cc: ...here.
* config/netbsd.c: Moved to...
* config/netbsd.cc: ...here.
* config/nios2/nios2.c: Moved to...
* config/nios2/nios2.cc: ...here.
* config/nvptx/mkoffload.c: Moved to...
* config/nvptx/mkoffload.cc: ...here.
* config/nvptx/nvptx-c.c: Moved to...
* config/nvptx/nvptx-c.cc: ...here.
* config/nvptx/nvptx.c: Moved to...
* config/nvptx/nvptx.cc: ...here.
* config/openbsd-d.c: Moved to...
* config/openbsd-d.cc: ...here.
* config/or1k/or1k.c: Moved to...
* config/or1k/or1k.cc: ...here.
* config/pa/pa-d.c: Moved to...
* config/pa/pa-d.cc: ...here.
* config/pa/pa.c: Moved to...
* config/pa/pa.cc: ...here.
* config/pdp11/pdp11.c: Moved to...
* config/pdp11/pdp11.cc: ...here.
* config/pru/pru-passes.c: Moved to...
* config/pru/pru-passes.cc: ...here.
* config/pru/pru-pragma.c: Moved to...
* config/pru/pru-pragma.cc: ...here.
* config/pru/pru.c: Moved to...
* config/pru/pru.cc: ...here.
* config/riscv/riscv-builtins.c: Moved to...
* config/riscv/riscv-builtins.cc: ...here.
* config/riscv/riscv-c.c: Moved to...
* config/riscv/riscv-c.cc: ...here.
* config/riscv/riscv-d.c: Moved to...
* config/riscv/riscv-d.cc: ...here.
* config/riscv/riscv-shorten-memrefs.c: Moved to...
* config/riscv/riscv-shorten-memrefs.cc: ...here.
* config/riscv/riscv-sr.c: Moved to...
* config/riscv/riscv-sr.cc: ...here.
* config/riscv/riscv.c: Moved to...
* config/riscv/riscv.cc: ...here.
* config/rl78/rl78-c.c: Moved to...
* config/rl78/rl78-c.cc: ...here.
* config/rl78/rl78.c: Moved to...
* config/rl78/rl78.cc: ...here.
* config/rs6000/driver-rs6000.c: Moved to...
* config/rs6000/driver-rs6000.cc: ...here.
* config/rs6000/host-darwin.c: Moved to...
* config/rs6000/host-darwin.cc: ...here.
* config/rs6000/host-ppc64-darwin.c: Moved to...
* config/rs6000/host-ppc64-darwin.cc: ...here.
* config/rs6000/rbtree.c: Moved to...
* config/rs6000/rbtree.cc: ...here.
* config/rs6000/rs6000-c.c: Moved to...
* config/rs6000/rs6000-c.cc: ...here.
* config/rs6000/rs6000-call.c: Moved to...
* config/rs6000/rs6000-call.cc: ...here.
* config/rs6000/rs6000-d.c: Moved to...
* config/rs6000/rs6000-d.cc: ...here.
* config/rs6000/rs6000-gen-builtins.c: Moved to...
* config/rs6000/rs6000-gen-builtins.cc: ...here.
* config/rs6000/rs6000-linux.c: Moved to...
* config/rs6000/rs6000-linux.cc: ...here.
* config/rs6000/rs6000-logue.c: Moved to...
* config/rs6000/rs6000-logue.cc: ...here.
* config/rs6000/rs6000-p8swap.c: Moved to...
* config/rs6000/rs6000-p8swap.cc: ...here.
* config/rs6000/rs6000-pcrel-opt.c: Moved to...
* config/rs6000/rs6000-pcrel-opt.cc: ...here.
* config/rs6000/rs6000-string.c: Moved to...
* config/rs6000/rs6000-string.cc: ...here.
* config/rs6000/rs6000.c: Moved to...
* config/rs6000/rs6000.cc: ...here.
* config/rx/rx.c: Moved to...
* config/rx/rx.cc: ...here.
* config/s390/driver-native.c: Moved to...
* config/s390/driver-native.cc: ...here.
* config/s390/s390-c.c: Moved to...
* config/s390/s390-c.cc: ...here.
* config/s390/s390-d.c: Moved to...
* config/s390/s390-d.cc: ...here.
* config/s390/s390.c: Moved to...
* config/s390/s390.cc: ...here.
* config/sh/divtab-sh4-300.c: Moved to...
* config/sh/divtab-sh4-300.cc: ...here.
* config/sh/divtab-sh4.c: Moved to...
* config/sh/divtab-sh4.cc: ...here.
* config/sh/divtab.c: Moved to...
* config/sh/divtab.cc: ...here.
* config/sh/sh-c.c: Moved to...
* config/sh/sh-c.cc: ...here.
* config/sh/sh.c: Moved to...
* config/sh/sh.cc: ...here.
* config/sol2-c.c: Moved to...
* config/sol2-c.cc: ...here.
* config/sol2-cxx.c: Moved to...
* config/sol2-cxx.cc: ...here.
* config/sol2-d.c: Moved to...
* config/sol2-d.cc: ...here.
* config/sol2-stubs.c: Moved to...
* config/sol2-stubs.cc: ...here.
* config/sol2.c: Moved to...
* config/sol2.cc: ...here.
* config/sparc/driver-sparc.c: Moved to...
* config/sparc/driver-sparc.cc: ...here.
* config/sparc/sparc-c.c: Moved to...
* config/sparc/sparc-c.cc: ...here.
* config/sparc/sparc-d.c: Moved to...
* config/sparc/sparc-d.cc: ...here.
* config/sparc/sparc.c: Moved to...
* config/sparc/sparc.cc: ...here.
* config/stormy16/stormy16.c: Moved to...
* config/stormy16/stormy16.cc: ...here.
* config/tilegx/mul-tables.c: Moved to...
* config/tilegx/mul-tables.cc: ...here.
* config/tilegx/tilegx-c.c: Moved to...
* config/tilegx/tilegx-c.cc: ...here.
* config/tilegx/tilegx.c: Moved to...
* config/tilegx/tilegx.cc: ...here.
* config/tilepro/mul-tables.c: Moved to...
* config/tilepro/mul-tables.cc: ...here.
* config/tilepro/tilepro-c.c: Moved to...
* config/tilepro/tilepro-c.cc: ...here.
* config/tilepro/tilepro.c: Moved to...
* config/tilepro/tilepro.cc: ...here.
* config/v850/v850-c.c: Moved to...
* config/v850/v850-c.cc: ...here.
* config/v850/v850.c: Moved to...
* config/v850/v850.cc: ...here.
* config/vax/vax.c: Moved to...
* config/vax/vax.cc: ...here.
* config/visium/visium.c: Moved to...
* config/visium/visium.cc: ...here.
* config/vms/vms-c.c: Moved to...
* config/vms/vms-c.cc: ...here.
* config/vms/vms-f.c: Moved to...
* config/vms/vms-f.cc: ...here.
* config/vms/vms.c: Moved to...
* config/vms/vms.cc: ...here.
* config/vxworks-c.c: Moved to...
* config/vxworks-c.cc: ...here.
* config/vxworks.c: Moved to...
* config/vxworks.cc: ...here.
* config/winnt-c.c: Moved to...
* config/winnt-c.cc: ...here.
* config/xtensa/xtensa.c: Moved to...
* config/xtensa/xtensa.cc: ...here.
* context.c: Moved to...
* context.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* coverage.c: Moved to...
* coverage.cc: ...here.
* cppbuiltin.c: Moved to...
* cppbuiltin.cc: ...here.
* cppdefault.c: Moved to...
* cppdefault.cc: ...here.
* cprop.c: Moved to...
* cprop.cc: ...here.
* cse.c: Moved to...
* cse.cc: ...here.
* cselib.c: Moved to...
* cselib.cc: ...here.
* ctfc.c: Moved to...
* ctfc.cc: ...here.
* ctfout.c: Moved to...
* ctfout.cc: ...here.
* data-streamer-in.c: Moved to...
* data-streamer-in.cc: ...here.
* data-streamer-out.c: Moved to...
* data-streamer-out.cc: ...here.
* data-streamer.c: Moved to...
* data-streamer.cc: ...here.
* dbgcnt.c: Moved to...
* dbgcnt.cc: ...here.
* dbxout.c: Moved to...
* dbxout.cc: ...here.
* dce.c: Moved to...
* dce.cc: ...here.
* ddg.c: Moved to...
* ddg.cc: ...here.
* debug.c: Moved to...
* debug.cc: ...here.
* df-core.c: Moved to...
* df-core.cc: ...here.
* df-problems.c: Moved to...
* df-problems.cc: ...here.
* df-scan.c: Moved to...
* df-scan.cc: ...here.
* dfp.c: Moved to...
* dfp.cc: ...here.
* diagnostic-color.c: Moved to...
* diagnostic-color.cc: ...here.
* diagnostic-show-locus.c: Moved to...
* diagnostic-show-locus.cc: ...here.
* diagnostic-spec.c: Moved to...
* diagnostic-spec.cc: ...here.
* diagnostic.c: Moved to...
* diagnostic.cc: ...here.
* dojump.c: Moved to...
* dojump.cc: ...here.
* dominance.c: Moved to...
* dominance.cc: ...here.
* domwalk.c: Moved to...
* domwalk.cc: ...here.
* double-int.c: Moved to...
* double-int.cc: ...here.
* dse.c: Moved to...
* dse.cc: ...here.
* dumpfile.c: Moved to...
* dumpfile.cc: ...here.
* dwarf2asm.c: Moved to...
* dwarf2asm.cc: ...here.
* dwarf2cfi.c: Moved to...
* dwarf2cfi.cc: ...here.
* dwarf2ctf.c: Moved to...
* dwarf2ctf.cc: ...here.
* dwarf2out.c: Moved to...
* dwarf2out.cc: ...here.
* early-remat.c: Moved to...
* early-remat.cc: ...here.
* edit-context.c: Moved to...
* edit-context.cc: ...here.
* emit-rtl.c: Moved to...
* emit-rtl.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* et-forest.c: Moved to...
* et-forest.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* explow.c: Moved to...
* explow.cc: ...here.
* expmed.c: Moved to...
* expmed.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* fibonacci_heap.c: Moved to...
* fibonacci_heap.cc: ...here.
* file-find.c: Moved to...
* file-find.cc: ...here.
* file-prefix-map.c: Moved to...
* file-prefix-map.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* fixed-value.c: Moved to...
* fixed-value.cc: ...here.
* fold-const-call.c: Moved to...
* fold-const-call.cc: ...here.
* fold-const.c: Moved to...
* fold-const.cc: ...here.
* fp-test.c: Moved to...
* fp-test.cc: ...here.
* function-tests.c: Moved to...
* function-tests.cc: ...here.
* function.c: Moved to...
* function.cc: ...here.
* fwprop.c: Moved to...
* fwprop.cc: ...here.
* gcc-ar.c: Moved to...
* gcc-ar.cc: ...here.
* gcc-main.c: Moved to...
* gcc-main.cc: ...here.
* gcc-rich-location.c: Moved to...
* gcc-rich-location.cc: ...here.
* gcc.c: Moved to...
* gcc.cc: ...here.
* gcov-dump.c: Moved to...
* gcov-dump.cc: ...here.
* gcov-io.c: Moved to...
* gcov-io.cc: ...here.
* gcov-tool.c: Moved to...
* gcov-tool.cc: ...here.
* gcov.c: Moved to...
* gcov.cc: ...here.
* gcse-common.c: Moved to...
* gcse-common.cc: ...here.
* gcse.c: Moved to...
* gcse.cc: ...here.
* genattr-common.c: Moved to...
* genattr-common.cc: ...here.
* genattr.c: Moved to...
* genattr.cc: ...here.
* genattrtab.c: Moved to...
* genattrtab.cc: ...here.
* genautomata.c: Moved to...
* genautomata.cc: ...here.
* gencfn-macros.c: Moved to...
* gencfn-macros.cc: ...here.
* gencheck.c: Moved to...
* gencheck.cc: ...here.
* genchecksum.c: Moved to...
* genchecksum.cc: ...here.
* gencodes.c: Moved to...
* gencodes.cc: ...here.
* genconditions.c: Moved to...
* genconditions.cc: ...here.
* genconfig.c: Moved to...
* genconfig.cc: ...here.
* genconstants.c: Moved to...
* genconstants.cc: ...here.
* genemit.c: Moved to...
* genemit.cc: ...here.
* genenums.c: Moved to...
* genenums.cc: ...here.
* generic-match-head.c: Moved to...
* generic-match-head.cc: ...here.
* genextract.c: Moved to...
* genextract.cc: ...here.
* genflags.c: Moved to...
* genflags.cc: ...here.
* gengenrtl.c: Moved to...
* gengenrtl.cc: ...here.
* gengtype-parse.c: Moved to...
* gengtype-parse.cc: ...here.
* gengtype-state.c: Moved to...
* gengtype-state.cc: ...here.
* gengtype.c: Moved to...
* gengtype.cc: ...here.
* genhooks.c: Moved to...
* genhooks.cc: ...here.
* genmatch.c: Moved to...
* genmatch.cc: ...here.
* genmddeps.c: Moved to...
* genmddeps.cc: ...here.
* genmddump.c: Moved to...
* genmddump.cc: ...here.
* genmodes.c: Moved to...
* genmodes.cc: ...here.
* genopinit.c: Moved to...
* genopinit.cc: ...here.
* genoutput.c: Moved to...
* genoutput.cc: ...here.
* genpeep.c: Moved to...
* genpeep.cc: ...here.
* genpreds.c: Moved to...
* genpreds.cc: ...here.
* genrecog.c: Moved to...
* genrecog.cc: ...here.
* gensupport.c: Moved to...
* gensupport.cc: ...here.
* gentarget-def.c: Moved to...
* gentarget-def.cc: ...here.
* genversion.c: Moved to...
* genversion.cc: ...here.
* ggc-common.c: Moved to...
* ggc-common.cc: ...here.
* ggc-none.c: Moved to...
* ggc-none.cc: ...here.
* ggc-page.c: Moved to...
* ggc-page.cc: ...here.
* ggc-tests.c: Moved to...
* ggc-tests.cc: ...here.
* gimple-builder.c: Moved to...
* gimple-builder.cc: ...here.
* gimple-expr.c: Moved to...
* gimple-expr.cc: ...here.
* gimple-fold.c: Moved to...
* gimple-fold.cc: ...here.
* gimple-iterator.c: Moved to...
* gimple-iterator.cc: ...here.
* gimple-laddress.c: Moved to...
* gimple-laddress.cc: ...here.
* gimple-loop-jam.c: Moved to...
* gimple-loop-jam.cc: ...here.
* gimple-low.c: Moved to...
* gimple-low.cc: ...here.
* gimple-match-head.c: Moved to...
* gimple-match-head.cc: ...here.
* gimple-pretty-print.c: Moved to...
* gimple-pretty-print.cc: ...here.
* gimple-ssa-backprop.c: Moved to...
* gimple-ssa-backprop.cc: ...here.
* gimple-ssa-evrp-analyze.c: Moved to...
* gimple-ssa-evrp-analyze.cc: ...here.
* gimple-ssa-evrp.c: Moved to...
* gimple-ssa-evrp.cc: ...here.
* gimple-ssa-isolate-paths.c: Moved to...
* gimple-ssa-isolate-paths.cc: ...here.
* gimple-ssa-nonnull-compare.c: Moved to...
* gimple-ssa-nonnull-compare.cc: ...here.
* gimple-ssa-split-paths.c: Moved to...
* gimple-ssa-split-paths.cc: ...here.
* gimple-ssa-sprintf.c: Moved to...
* gimple-ssa-sprintf.cc: ...here.
* gimple-ssa-store-merging.c: Moved to...
* gimple-ssa-store-merging.cc: ...here.
* gimple-ssa-strength-reduction.c: Moved to...
* gimple-ssa-strength-reduction.cc: ...here.
* gimple-ssa-warn-alloca.c: Moved to...
* gimple-ssa-warn-alloca.cc: ...here.
* gimple-ssa-warn-restrict.c: Moved to...
* gimple-ssa-warn-restrict.cc: ...here.
* gimple-streamer-in.c: Moved to...
* gimple-streamer-in.cc: ...here.
* gimple-streamer-out.c: Moved to...
* gimple-streamer-out.cc: ...here.
* gimple-walk.c: Moved to...
* gimple-walk.cc: ...here.
* gimple-warn-recursion.c: Moved to...
* gimple-warn-recursion.cc: ...here.
* gimple.c: Moved to...
* gimple.cc: ...here.
* gimplify-me.c: Moved to...
* gimplify-me.cc: ...here.
* gimplify.c: Moved to...
* gimplify.cc: ...here.
* godump.c: Moved to...
* godump.cc: ...here.
* graph.c: Moved to...
* graph.cc: ...here.
* graphds.c: Moved to...
* graphds.cc: ...here.
* graphite-dependences.c: Moved to...
* graphite-dependences.cc: ...here.
* graphite-isl-ast-to-gimple.c: Moved to...
* graphite-isl-ast-to-gimple.cc: ...here.
* graphite-optimize-isl.c: Moved to...
* graphite-optimize-isl.cc: ...here.
* graphite-poly.c: Moved to...
* graphite-poly.cc: ...here.
* graphite-scop-detection.c: Moved to...
* graphite-scop-detection.cc: ...here.
* graphite-sese-to-poly.c: Moved to...
* graphite-sese-to-poly.cc: ...here.
* graphite.c: Moved to...
* graphite.cc: ...here.
* haifa-sched.c: Moved to...
* haifa-sched.cc: ...here.
* hash-map-tests.c: Moved to...
* hash-map-tests.cc: ...here.
* hash-set-tests.c: Moved to...
* hash-set-tests.cc: ...here.
* hash-table.c: Moved to...
* hash-table.cc: ...here.
* hooks.c: Moved to...
* hooks.cc: ...here.
* host-default.c: Moved to...
* host-default.cc: ...here.
* hw-doloop.c: Moved to...
* hw-doloop.cc: ...here.
* hwint.c: Moved to...
* hwint.cc: ...here.
* ifcvt.c: Moved to...
* ifcvt.cc: ...here.
* inchash.c: Moved to...
* inchash.cc: ...here.
* incpath.c: Moved to...
* incpath.cc: ...here.
* init-regs.c: Moved to...
* init-regs.cc: ...here.
* input.c: Moved to...
* input.cc: ...here.
* internal-fn.c: Moved to...
* internal-fn.cc: ...here.
* intl.c: Moved to...
* intl.cc: ...here.
* ipa-comdats.c: Moved to...
* ipa-comdats.cc: ...here.
* ipa-cp.c: Moved to...
* ipa-cp.cc: ...here.
* ipa-devirt.c: Moved to...
* ipa-devirt.cc: ...here.
* ipa-fnsummary.c: Moved to...
* ipa-fnsummary.cc: ...here.
* ipa-icf-gimple.c: Moved to...
* ipa-icf-gimple.cc: ...here.
* ipa-icf.c: Moved to...
* ipa-icf.cc: ...here.
* ipa-inline-analysis.c: Moved to...
* ipa-inline-analysis.cc: ...here.
* ipa-inline-transform.c: Moved to...
* ipa-inline-transform.cc: ...here.
* ipa-inline.c: Moved to...
* ipa-inline.cc: ...here.
* ipa-modref-tree.c: Moved to...
* ipa-modref-tree.cc: ...here.
* ipa-modref.c: Moved to...
* ipa-modref.cc: ...here.
* ipa-param-manipulation.c: Moved to...
* ipa-param-manipulation.cc: ...here.
* ipa-polymorphic-call.c: Moved to...
* ipa-polymorphic-call.cc: ...here.
* ipa-predicate.c: Moved to...
* ipa-predicate.cc: ...here.
* ipa-profile.c: Moved to...
* ipa-profile.cc: ...here.
* ipa-prop.c: Moved to...
* ipa-prop.cc: ...here.
* ipa-pure-const.c: Moved to...
* ipa-pure-const.cc: ...here.
* ipa-ref.c: Moved to...
* ipa-ref.cc: ...here.
* ipa-reference.c: Moved to...
* ipa-reference.cc: ...here.
* ipa-split.c: Moved to...
* ipa-split.cc: ...here.
* ipa-sra.c: Moved to...
* ipa-sra.cc: ...here.
* ipa-utils.c: Moved to...
* ipa-utils.cc: ...here.
* ipa-visibility.c: Moved to...
* ipa-visibility.cc: ...here.
* ipa.c: Moved to...
* ipa.cc: ...here.
* ira-build.c: Moved to...
* ira-build.cc: ...here.
* ira-color.c: Moved to...
* ira-color.cc: ...here.
* ira-conflicts.c: Moved to...
* ira-conflicts.cc: ...here.
* ira-costs.c: Moved to...
* ira-costs.cc: ...here.
* ira-emit.c: Moved to...
* ira-emit.cc: ...here.
* ira-lives.c: Moved to...
* ira-lives.cc: ...here.
* ira.c: Moved to...
* ira.cc: ...here.
* jump.c: Moved to...
* jump.cc: ...here.
* langhooks.c: Moved to...
* langhooks.cc: ...here.
* lcm.c: Moved to...
* lcm.cc: ...here.
* lists.c: Moved to...
* lists.cc: ...here.
* loop-doloop.c: Moved to...
* loop-doloop.cc: ...here.
* loop-init.c: Moved to...
* loop-init.cc: ...here.
* loop-invariant.c: Moved to...
* loop-invariant.cc: ...here.
* loop-iv.c: Moved to...
* loop-iv.cc: ...here.
* loop-unroll.c: Moved to...
* loop-unroll.cc: ...here.
* lower-subreg.c: Moved to...
* lower-subreg.cc: ...here.
* lra-assigns.c: Moved to...
* lra-assigns.cc: ...here.
* lra-coalesce.c: Moved to...
* lra-coalesce.cc: ...here.
* lra-constraints.c: Moved to...
* lra-constraints.cc: ...here.
* lra-eliminations.c: Moved to...
* lra-eliminations.cc: ...here.
* lra-lives.c: Moved to...
* lra-lives.cc: ...here.
* lra-remat.c: Moved to...
* lra-remat.cc: ...here.
* lra-spills.c: Moved to...
* lra-spills.cc: ...here.
* lra.c: Moved to...
* lra.cc: ...here.
* lto-cgraph.c: Moved to...
* lto-cgraph.cc: ...here.
* lto-compress.c: Moved to...
* lto-compress.cc: ...here.
* lto-opts.c: Moved to...
* lto-opts.cc: ...here.
* lto-section-in.c: Moved to...
* lto-section-in.cc: ...here.
* lto-section-out.c: Moved to...
* lto-section-out.cc: ...here.
* lto-streamer-in.c: Moved to...
* lto-streamer-in.cc: ...here.
* lto-streamer-out.c: Moved to...
* lto-streamer-out.cc: ...here.
* lto-streamer.c: Moved to...
* lto-streamer.cc: ...here.
* lto-wrapper.c: Moved to...
* lto-wrapper.cc: ...here.
* main.c: Moved to...
* main.cc: ...here.
* mcf.c: Moved to...
* mcf.cc: ...here.
* mode-switching.c: Moved to...
* mode-switching.cc: ...here.
* modulo-sched.c: Moved to...
* modulo-sched.cc: ...here.
* multiple_target.c: Moved to...
* multiple_target.cc: ...here.
* omp-expand.c: Moved to...
* omp-expand.cc: ...here.
* omp-general.c: Moved to...
* omp-general.cc: ...here.
* omp-low.c: Moved to...
* omp-low.cc: ...here.
* omp-offload.c: Moved to...
* omp-offload.cc: ...here.
* omp-simd-clone.c: Moved to...
* omp-simd-clone.cc: ...here.
* opt-suggestions.c: Moved to...
* opt-suggestions.cc: ...here.
* optabs-libfuncs.c: Moved to...
* optabs-libfuncs.cc: ...here.
* optabs-query.c: Moved to...
* optabs-query.cc: ...here.
* optabs-tree.c: Moved to...
* optabs-tree.cc: ...here.
* optabs.c: Moved to...
* optabs.cc: ...here.
* opts-common.c: Moved to...
* opts-common.cc: ...here.
* opts-global.c: Moved to...
* opts-global.cc: ...here.
* opts.c: Moved to...
* opts.cc: ...here.
* passes.c: Moved to...
* passes.cc: ...here.
* plugin.c: Moved to...
* plugin.cc: ...here.
* postreload-gcse.c: Moved to...
* postreload-gcse.cc: ...here.
* postreload.c: Moved to...
* postreload.cc: ...here.
* predict.c: Moved to...
* predict.cc: ...here.
* prefix.c: Moved to...
* prefix.cc: ...here.
* pretty-print.c: Moved to...
* pretty-print.cc: ...here.
* print-rtl-function.c: Moved to...
* print-rtl-function.cc: ...here.
* print-rtl.c: Moved to...
* print-rtl.cc: ...here.
* print-tree.c: Moved to...
* print-tree.cc: ...here.
* profile-count.c: Moved to...
* profile-count.cc: ...here.
* profile.c: Moved to...
* profile.cc: ...here.
* read-md.c: Moved to...
* read-md.cc: ...here.
* read-rtl-function.c: Moved to...
* read-rtl-function.cc: ...here.
* read-rtl.c: Moved to...
* read-rtl.cc: ...here.
* real.c: Moved to...
* real.cc: ...here.
* realmpfr.c: Moved to...
* realmpfr.cc: ...here.
* recog.c: Moved to...
* recog.cc: ...here.
* ree.c: Moved to...
* ree.cc: ...here.
* reg-stack.c: Moved to...
* reg-stack.cc: ...here.
* regcprop.c: Moved to...
* regcprop.cc: ...here.
* reginfo.c: Moved to...
* reginfo.cc: ...here.
* regrename.c: Moved to...
* regrename.cc: ...here.
* regstat.c: Moved to...
* regstat.cc: ...here.
* reload.c: Moved to...
* reload.cc: ...here.
* reload1.c: Moved to...
* reload1.cc: ...here.
* reorg.c: Moved to...
* reorg.cc: ...here.
* resource.c: Moved to...
* resource.cc: ...here.
* rtl-error.c: Moved to...
* rtl-error.cc: ...here.
* rtl-tests.c: Moved to...
* rtl-tests.cc: ...here.
* rtl.c: Moved to...
* rtl.cc: ...here.
* rtlanal.c: Moved to...
* rtlanal.cc: ...here.
* rtlhash.c: Moved to...
* rtlhash.cc: ...here.
* rtlhooks.c: Moved to...
* rtlhooks.cc: ...here.
* rtx-vector-builder.c: Moved to...
* rtx-vector-builder.cc: ...here.
* run-rtl-passes.c: Moved to...
* run-rtl-passes.cc: ...here.
* sancov.c: Moved to...
* sancov.cc: ...here.
* sanopt.c: Moved to...
* sanopt.cc: ...here.
* sbitmap.c: Moved to...
* sbitmap.cc: ...here.
* sched-deps.c: Moved to...
* sched-deps.cc: ...here.
* sched-ebb.c: Moved to...
* sched-ebb.cc: ...here.
* sched-rgn.c: Moved to...
* sched-rgn.cc: ...here.
* sel-sched-dump.c: Moved to...
* sel-sched-dump.cc: ...here.
* sel-sched-ir.c: Moved to...
* sel-sched-ir.cc: ...here.
* sel-sched.c: Moved to...
* sel-sched.cc: ...here.
* selftest-diagnostic.c: Moved to...
* selftest-diagnostic.cc: ...here.
* selftest-rtl.c: Moved to...
* selftest-rtl.cc: ...here.
* selftest-run-tests.c: Moved to...
* selftest-run-tests.cc: ...here.
* selftest.c: Moved to...
* selftest.cc: ...here.
* sese.c: Moved to...
* sese.cc: ...here.
* shrink-wrap.c: Moved to...
* shrink-wrap.cc: ...here.
* simplify-rtx.c: Moved to...
* simplify-rtx.cc: ...here.
* sparseset.c: Moved to...
* sparseset.cc: ...here.
* spellcheck-tree.c: Moved to...
* spellcheck-tree.cc: ...here.
* spellcheck.c: Moved to...
* spellcheck.cc: ...here.
* sreal.c: Moved to...
* sreal.cc: ...here.
* stack-ptr-mod.c: Moved to...
* stack-ptr-mod.cc: ...here.
* statistics.c: Moved to...
* statistics.cc: ...here.
* stmt.c: Moved to...
* stmt.cc: ...here.
* stor-layout.c: Moved to...
* stor-layout.cc: ...here.
* store-motion.c: Moved to...
* store-motion.cc: ...here.
* streamer-hooks.c: Moved to...
* streamer-hooks.cc: ...here.
* stringpool.c: Moved to...
* stringpool.cc: ...here.
* substring-locations.c: Moved to...
* substring-locations.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* target-globals.c: Moved to...
* target-globals.cc: ...here.
* targhooks.c: Moved to...
* targhooks.cc: ...here.
* timevar.c: Moved to...
* timevar.cc: ...here.
* toplev.c: Moved to...
* toplev.cc: ...here.
* tracer.c: Moved to...
* tracer.cc: ...here.
* trans-mem.c: Moved to...
* trans-mem.cc: ...here.
* tree-affine.c: Moved to...
* tree-affine.cc: ...here.
* tree-call-cdce.c: Moved to...
* tree-call-cdce.cc: ...here.
* tree-cfg.c: Moved to...
* tree-cfg.cc: ...here.
* tree-cfgcleanup.c: Moved to...
* tree-cfgcleanup.cc: ...here.
* tree-chrec.c: Moved to...
* tree-chrec.cc: ...here.
* tree-complex.c: Moved to...
* tree-complex.cc: ...here.
* tree-data-ref.c: Moved to...
* tree-data-ref.cc: ...here.
* tree-dfa.c: Moved to...
* tree-dfa.cc: ...here.
* tree-diagnostic.c: Moved to...
* tree-diagnostic.cc: ...here.
* tree-dump.c: Moved to...
* tree-dump.cc: ...here.
* tree-eh.c: Moved to...
* tree-eh.cc: ...here.
* tree-emutls.c: Moved to...
* tree-emutls.cc: ...here.
* tree-if-conv.c: Moved to...
* tree-if-conv.cc: ...here.
* tree-inline.c: Moved to...
* tree-inline.cc: ...here.
* tree-into-ssa.c: Moved to...
* tree-into-ssa.cc: ...here.
* tree-iterator.c: Moved to...
* tree-iterator.cc: ...here.
* tree-loop-distribution.c: Moved to...
* tree-loop-distribution.cc: ...here.
* tree-nested.c: Moved to...
* tree-nested.cc: ...here.
* tree-nrv.c: Moved to...
* tree-nrv.cc: ...here.
* tree-object-size.c: Moved to...
* tree-object-size.cc: ...here.
* tree-outof-ssa.c: Moved to...
* tree-outof-ssa.cc: ...here.
* tree-parloops.c: Moved to...
* tree-parloops.cc: ...here.
* tree-phinodes.c: Moved to...
* tree-phinodes.cc: ...here.
* tree-predcom.c: Moved to...
* tree-predcom.cc: ...here.
* tree-pretty-print.c: Moved to...
* tree-pretty-print.cc: ...here.
* tree-profile.c: Moved to...
* tree-profile.cc: ...here.
* tree-scalar-evolution.c: Moved to...
* tree-scalar-evolution.cc: ...here.
* tree-sra.c: Moved to...
* tree-sra.cc: ...here.
* tree-ssa-address.c: Moved to...
* tree-ssa-address.cc: ...here.
* tree-ssa-alias.c: Moved to...
* tree-ssa-alias.cc: ...here.
* tree-ssa-ccp.c: Moved to...
* tree-ssa-ccp.cc: ...here.
* tree-ssa-coalesce.c: Moved to...
* tree-ssa-coalesce.cc: ...here.
* tree-ssa-copy.c: Moved to...
* tree-ssa-copy.cc: ...here.
* tree-ssa-dce.c: Moved to...
* tree-ssa-dce.cc: ...here.
* tree-ssa-dom.c: Moved to...
* tree-ssa-dom.cc: ...here.
* tree-ssa-dse.c: Moved to...
* tree-ssa-dse.cc: ...here.
* tree-ssa-forwprop.c: Moved to...
* tree-ssa-forwprop.cc: ...here.
* tree-ssa-ifcombine.c: Moved to...
* tree-ssa-ifcombine.cc: ...here.
* tree-ssa-live.c: Moved to...
* tree-ssa-live.cc: ...here.
* tree-ssa-loop-ch.c: Moved to...
* tree-ssa-loop-ch.cc: ...here.
* tree-ssa-loop-im.c: Moved to...
* tree-ssa-loop-im.cc: ...here.
* tree-ssa-loop-ivcanon.c: Moved to...
* tree-ssa-loop-ivcanon.cc: ...here.
* tree-ssa-loop-ivopts.c: Moved to...
* tree-ssa-loop-ivopts.cc: ...here.
* tree-ssa-loop-manip.c: Moved to...
* tree-ssa-loop-manip.cc: ...here.
* tree-ssa-loop-niter.c: Moved to...
* tree-ssa-loop-niter.cc: ...here.
* tree-ssa-loop-prefetch.c: Moved to...
* tree-ssa-loop-prefetch.cc: ...here.
* tree-ssa-loop-split.c: Moved to...
* tree-ssa-loop-split.cc: ...here.
* tree-ssa-loop-unswitch.c: Moved to...
* tree-ssa-loop-unswitch.cc: ...here.
* tree-ssa-loop.c: Moved to...
* tree-ssa-loop.cc: ...here.
* tree-ssa-math-opts.c: Moved to...
* tree-ssa-math-opts.cc: ...here.
* tree-ssa-operands.c: Moved to...
* tree-ssa-operands.cc: ...here.
* tree-ssa-phiopt.c: Moved to...
* tree-ssa-phiopt.cc: ...here.
* tree-ssa-phiprop.c: Moved to...
* tree-ssa-phiprop.cc: ...here.
* tree-ssa-pre.c: Moved to...
* tree-ssa-pre.cc: ...here.
* tree-ssa-propagate.c: Moved to...
* tree-ssa-propagate.cc: ...here.
* tree-ssa-reassoc.c: Moved to...
* tree-ssa-reassoc.cc: ...here.
* tree-ssa-sccvn.c: Moved to...
* tree-ssa-sccvn.cc: ...here.
* tree-ssa-scopedtables.c: Moved to...
* tree-ssa-scopedtables.cc: ...here.
* tree-ssa-sink.c: Moved to...
* tree-ssa-sink.cc: ...here.
* tree-ssa-strlen.c: Moved to...
* tree-ssa-strlen.cc: ...here.
* tree-ssa-structalias.c: Moved to...
* tree-ssa-structalias.cc: ...here.
* tree-ssa-tail-merge.c: Moved to...
* tree-ssa-tail-merge.cc: ...here.
* tree-ssa-ter.c: Moved to...
* tree-ssa-ter.cc: ...here.
* tree-ssa-threadbackward.c: Moved to...
* tree-ssa-threadbackward.cc: ...here.
* tree-ssa-threadedge.c: Moved to...
* tree-ssa-threadedge.cc: ...here.
* tree-ssa-threadupdate.c: Moved to...
* tree-ssa-threadupdate.cc: ...here.
* tree-ssa-uncprop.c: Moved to...
* tree-ssa-uncprop.cc: ...here.
* tree-ssa-uninit.c: Moved to...
* tree-ssa-uninit.cc: ...here.
* tree-ssa.c: Moved to...
* tree-ssa.cc: ...here.
* tree-ssanames.c: Moved to...
* tree-ssanames.cc: ...here.
* tree-stdarg.c: Moved to...
* tree-stdarg.cc: ...here.
* tree-streamer-in.c: Moved to...
* tree-streamer-in.cc: ...here.
* tree-streamer-out.c: Moved to...
* tree-streamer-out.cc: ...here.
* tree-streamer.c: Moved to...
* tree-streamer.cc: ...here.
* tree-switch-conversion.c: Moved to...
* tree-switch-conversion.cc: ...here.
* tree-tailcall.c: Moved to...
* tree-tailcall.cc: ...here.
* tree-vect-data-refs.c: Moved to...
* tree-vect-data-refs.cc: ...here.
* tree-vect-generic.c: Moved to...
* tree-vect-generic.cc: ...here.
* tree-vect-loop-manip.c: Moved to...
* tree-vect-loop-manip.cc: ...here.
* tree-vect-loop.c: Moved to...
* tree-vect-loop.cc: ...here.
* tree-vect-patterns.c: Moved to...
* tree-vect-patterns.cc: ...here.
* tree-vect-slp-patterns.c: Moved to...
* tree-vect-slp-patterns.cc: ...here.
* tree-vect-slp.c: Moved to...
* tree-vect-slp.cc: ...here.
* tree-vect-stmts.c: Moved to...
* tree-vect-stmts.cc: ...here.
* tree-vector-builder.c: Moved to...
* tree-vector-builder.cc: ...here.
* tree-vectorizer.c: Moved to...
* tree-vectorizer.cc: ...here.
* tree-vrp.c: Moved to...
* tree-vrp.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* tsan.c: Moved to...
* tsan.cc: ...here.
* typed-splay-tree.c: Moved to...
* typed-splay-tree.cc: ...here.
* ubsan.c: Moved to...
* ubsan.cc: ...here.
* valtrack.c: Moved to...
* valtrack.cc: ...here.
* value-prof.c: Moved to...
* value-prof.cc: ...here.
* var-tracking.c: Moved to...
* var-tracking.cc: ...here.
* varasm.c: Moved to...
* varasm.cc: ...here.
* varpool.c: Moved to...
* varpool.cc: ...here.
* vec-perm-indices.c: Moved to...
* vec-perm-indices.cc: ...here.
* vec.c: Moved to...
* vec.cc: ...here.
* vmsdbgout.c: Moved to...
* vmsdbgout.cc: ...here.
* vr-values.c: Moved to...
* vr-values.cc: ...here.
* vtable-verify.c: Moved to...
* vtable-verify.cc: ...here.
* web.c: Moved to...
* web.cc: ...here.
* xcoffout.c: Moved to...
* xcoffout.cc: ...here.
gcc/c-family/ChangeLog:
* c-ada-spec.c: Moved to...
* c-ada-spec.cc: ...here.
* c-attribs.c: Moved to...
* c-attribs.cc: ...here.
* c-common.c: Moved to...
* c-common.cc: ...here.
* c-cppbuiltin.c: Moved to...
* c-cppbuiltin.cc: ...here.
* c-dump.c: Moved to...
* c-dump.cc: ...here.
* c-format.c: Moved to...
* c-format.cc: ...here.
* c-gimplify.c: Moved to...
* c-gimplify.cc: ...here.
* c-indentation.c: Moved to...
* c-indentation.cc: ...here.
* c-lex.c: Moved to...
* c-lex.cc: ...here.
* c-omp.c: Moved to...
* c-omp.cc: ...here.
* c-opts.c: Moved to...
* c-opts.cc: ...here.
* c-pch.c: Moved to...
* c-pch.cc: ...here.
* c-ppoutput.c: Moved to...
* c-ppoutput.cc: ...here.
* c-pragma.c: Moved to...
* c-pragma.cc: ...here.
* c-pretty-print.c: Moved to...
* c-pretty-print.cc: ...here.
* c-semantics.c: Moved to...
* c-semantics.cc: ...here.
* c-ubsan.c: Moved to...
* c-ubsan.cc: ...here.
* c-warn.c: Moved to...
* c-warn.cc: ...here.
* cppspec.c: Moved to...
* cppspec.cc: ...here.
* stub-objc.c: Moved to...
* stub-objc.cc: ...here.
gcc/c/ChangeLog:
* c-aux-info.c: Moved to...
* c-aux-info.cc: ...here.
* c-convert.c: Moved to...
* c-convert.cc: ...here.
* c-decl.c: Moved to...
* c-decl.cc: ...here.
* c-errors.c: Moved to...
* c-errors.cc: ...here.
* c-fold.c: Moved to...
* c-fold.cc: ...here.
* c-lang.c: Moved to...
* c-lang.cc: ...here.
* c-objc-common.c: Moved to...
* c-objc-common.cc: ...here.
* c-parser.c: Moved to...
* c-parser.cc: ...here.
* c-typeck.c: Moved to...
* c-typeck.cc: ...here.
* gccspec.c: Moved to...
* gccspec.cc: ...here.
* gimple-parser.c: Moved to...
* gimple-parser.cc: ...here.
gcc/cp/ChangeLog:
* call.c: Moved to...
* call.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constexpr.c: Moved to...
* constexpr.cc: ...here.
* cp-gimplify.c: Moved to...
* cp-gimplify.cc: ...here.
* cp-lang.c: Moved to...
* cp-lang.cc: ...here.
* cp-objcp-common.c: Moved to...
* cp-objcp-common.cc: ...here.
* cp-ubsan.c: Moved to...
* cp-ubsan.cc: ...here.
* cvt.c: Moved to...
* cvt.cc: ...here.
* cxx-pretty-print.c: Moved to...
* cxx-pretty-print.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* decl2.c: Moved to...
* decl2.cc: ...here.
* dump.c: Moved to...
* dump.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* friend.c: Moved to...
* friend.cc: ...here.
* g++spec.c: Moved to...
* g++spec.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lambda.c: Moved to...
* lambda.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* mangle.c: Moved to...
* mangle.cc: ...here.
* method.c: Moved to...
* method.cc: ...here.
* name-lookup.c: Moved to...
* name-lookup.cc: ...here.
* optimize.c: Moved to...
* optimize.cc: ...here.
* parser.c: Moved to...
* parser.cc: ...here.
* pt.c: Moved to...
* pt.cc: ...here.
* ptree.c: Moved to...
* ptree.cc: ...here.
* rtti.c: Moved to...
* rtti.cc: ...here.
* search.c: Moved to...
* search.cc: ...here.
* semantics.c: Moved to...
* semantics.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* typeck.c: Moved to...
* typeck.cc: ...here.
* typeck2.c: Moved to...
* typeck2.cc: ...here.
* vtable-class-hierarchy.c: Moved to...
* vtable-class-hierarchy.cc: ...here.
gcc/fortran/ChangeLog:
* arith.c: Moved to...
* arith.cc: ...here.
* array.c: Moved to...
* array.cc: ...here.
* bbt.c: Moved to...
* bbt.cc: ...here.
* check.c: Moved to...
* check.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constructor.c: Moved to...
* constructor.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* cpp.c: Moved to...
* cpp.cc: ...here.
* data.c: Moved to...
* data.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* dependency.c: Moved to...
* dependency.cc: ...here.
* dump-parse-tree.c: Moved to...
* dump-parse-tree.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* f95-lang.c: Moved to...
* f95-lang.cc: ...here.
* frontend-passes.c: Moved to...
* frontend-passes.cc: ...here.
* gfortranspec.c: Moved to...
* gfortranspec.cc: ...here.
* interface.c: Moved to...
* interface.cc: ...here.
* intrinsic.c: Moved to...
* intrinsic.cc: ...here.
* io.c: Moved to...
* io.cc: ...here.
* iresolve.c: Moved to...
* iresolve.cc: ...here.
* match.c: Moved to...
* match.cc: ...here.
* matchexp.c: Moved to...
* matchexp.cc: ...here.
* misc.c: Moved to...
* misc.cc: ...here.
* module.c: Moved to...
* module.cc: ...here.
* openmp.c: Moved to...
* openmp.cc: ...here.
* options.c: Moved to...
* options.cc: ...here.
* parse.c: Moved to...
* parse.cc: ...here.
* primary.c: Moved to...
* primary.cc: ...here.
* resolve.c: Moved to...
* resolve.cc: ...here.
* scanner.c: Moved to...
* scanner.cc: ...here.
* simplify.c: Moved to...
* simplify.cc: ...here.
* st.c: Moved to...
* st.cc: ...here.
* symbol.c: Moved to...
* symbol.cc: ...here.
* target-memory.c: Moved to...
* target-memory.cc: ...here.
* trans-array.c: Moved to...
* trans-array.cc: ...here.
* trans-common.c: Moved to...
* trans-common.cc: ...here.
* trans-const.c: Moved to...
* trans-const.cc: ...here.
* trans-decl.c: Moved to...
* trans-decl.cc: ...here.
* trans-expr.c: Moved to...
* trans-expr.cc: ...here.
* trans-intrinsic.c: Moved to...
* trans-intrinsic.cc: ...here.
* trans-io.c: Moved to...
* trans-io.cc: ...here.
* trans-openmp.c: Moved to...
* trans-openmp.cc: ...here.
* trans-stmt.c: Moved to...
* trans-stmt.cc: ...here.
* trans-types.c: Moved to...
* trans-types.cc: ...here.
* trans.c: Moved to...
* trans.cc: ...here.
gcc/go/ChangeLog:
* go-backend.c: Moved to...
* go-backend.cc: ...here.
* go-lang.c: Moved to...
* go-lang.cc: ...here.
* gospec.c: Moved to...
* gospec.cc: ...here.
gcc/jit/ChangeLog:
* dummy-frontend.c: Moved to...
* dummy-frontend.cc: ...here.
* jit-builtins.c: Moved to...
* jit-builtins.cc: ...here.
* jit-logging.c: Moved to...
* jit-logging.cc: ...here.
* jit-playback.c: Moved to...
* jit-playback.cc: ...here.
* jit-recording.c: Moved to...
* jit-recording.cc: ...here.
* jit-result.c: Moved to...
* jit-result.cc: ...here.
* jit-spec.c: Moved to...
* jit-spec.cc: ...here.
* jit-tempdir.c: Moved to...
* jit-tempdir.cc: ...here.
* jit-w32.c: Moved to...
* jit-w32.cc: ...here.
* libgccjit.c: Moved to...
* libgccjit.cc: ...here.
gcc/lto/ChangeLog:
* common.c: Moved to...
* common.cc: ...here.
* lto-common.c: Moved to...
* lto-common.cc: ...here.
* lto-dump.c: Moved to...
* lto-dump.cc: ...here.
* lto-lang.c: Moved to...
* lto-lang.cc: ...here.
* lto-object.c: Moved to...
* lto-object.cc: ...here.
* lto-partition.c: Moved to...
* lto-partition.cc: ...here.
* lto-symtab.c: Moved to...
* lto-symtab.cc: ...here.
* lto.c: Moved to...
* lto.cc: ...here.
gcc/objc/ChangeLog:
* objc-act.c: Moved to...
* objc-act.cc: ...here.
* objc-encoding.c: Moved to...
* objc-encoding.cc: ...here.
* objc-gnu-runtime-abi-01.c: Moved to...
* objc-gnu-runtime-abi-01.cc: ...here.
* objc-lang.c: Moved to...
* objc-lang.cc: ...here.
* objc-map.c: Moved to...
* objc-map.cc: ...here.
* objc-next-runtime-abi-01.c: Moved to...
* objc-next-runtime-abi-01.cc: ...here.
* objc-next-runtime-abi-02.c: Moved to...
* objc-next-runtime-abi-02.cc: ...here.
* objc-runtime-shared-support.c: Moved to...
* objc-runtime-shared-support.cc: ...here.
gcc/objcp/ChangeLog:
* objcp-decl.c: Moved to...
* objcp-decl.cc: ...here.
* objcp-lang.c: Moved to...
* objcp-lang.cc: ...here.
libcpp/ChangeLog:
* charset.c: Moved to...
* charset.cc: ...here.
* directives.c: Moved to...
* directives.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* files.c: Moved to...
* files.cc: ...here.
* identifiers.c: Moved to...
* identifiers.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* line-map.c: Moved to...
* line-map.cc: ...here.
* macro.c: Moved to...
* macro.cc: ...here.
* makeucnid.c: Moved to...
* makeucnid.cc: ...here.
* mkdeps.c: Moved to...
* mkdeps.cc: ...here.
* pch.c: Moved to...
* pch.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* traditional.c: Moved to...
* traditional.cc: ...here.
Diffstat (limited to 'gcc/gimple-ssa-sprintf.c')
-rw-r--r-- | gcc/gimple-ssa-sprintf.c | 4728 |
1 files changed, 0 insertions, 4728 deletions
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c deleted file mode 100644 index 1f756b7..0000000 --- a/gcc/gimple-ssa-sprintf.c +++ /dev/null @@ -1,4728 +0,0 @@ -/* Copyright (C) 2016-2022 Free Software Foundation, Inc. - Contributed by Martin Sebor <msebor@redhat.com>. - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC 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 General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -/* This file implements the printf-return-value pass. The pass does - two things: 1) it analyzes calls to formatted output functions like - sprintf looking for possible buffer overflows and calls to bounded - functions like snprintf for early truncation (and under the control - of the -Wformat-length option issues warnings), and 2) under the - control of the -fprintf-return-value option it folds the return - value of safe calls into constants, making it possible to eliminate - code that depends on the value of those constants. - - For all functions (bounded or not) the pass uses the size of the - destination object. That means that it will diagnose calls to - snprintf not on the basis of the size specified by the function's - second argument but rather on the basis of the size the first - argument points to (if possible). For bound-checking built-ins - like __builtin___snprintf_chk the pass uses the size typically - determined by __builtin_object_size and passed to the built-in - by the Glibc inline wrapper. - - The pass handles all forms standard sprintf format directives, - including character, integer, floating point, pointer, and strings, - with the standard C flags, widths, and precisions. For integers - and strings it computes the length of output itself. For floating - point it uses MPFR to format known constants with up and down - rounding and uses the resulting range of output lengths. For - strings it uses the length of string literals and the sizes of - character arrays that a character pointer may point to as a bound - on the longest string. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "tree.h" -#include "gimple.h" -#include "tree-pass.h" -#include "ssa.h" -#include "gimple-fold.h" -#include "gimple-pretty-print.h" -#include "diagnostic-core.h" -#include "fold-const.h" -#include "gimple-iterator.h" -#include "tree-ssa.h" -#include "tree-object-size.h" -#include "tree-cfg.h" -#include "tree-ssa-propagate.h" -#include "calls.h" -#include "cfgloop.h" -#include "tree-scalar-evolution.h" -#include "tree-ssa-loop.h" -#include "intl.h" -#include "langhooks.h" - -#include "attribs.h" -#include "builtins.h" -#include "pointer-query.h" -#include "stor-layout.h" - -#include "realmpfr.h" -#include "target.h" - -#include "cpplib.h" -#include "input.h" -#include "toplev.h" -#include "substring-locations.h" -#include "diagnostic.h" -#include "domwalk.h" -#include "alloc-pool.h" -#include "vr-values.h" -#include "tree-ssa-strlen.h" -#include "tree-dfa.h" - -/* The likely worst case value of MB_LEN_MAX for the target, large enough - for UTF-8. Ideally, this would be obtained by a target hook if it were - to be used for optimization but it's good enough as is for warnings. */ -#define target_mb_len_max() 6 - -/* The maximum number of bytes a single non-string directive can result - in. This is the result of printf("%.*Lf", INT_MAX, -LDBL_MAX) for - LDBL_MAX_10_EXP of 4932. */ -#define IEEE_MAX_10_EXP 4932 -#define target_dir_max() (target_int_max () + IEEE_MAX_10_EXP + 2) - -namespace { - -/* Set to the warning level for the current function which is equal - either to warn_format_trunc for bounded functions or to - warn_format_overflow otherwise. */ - -static int warn_level; - -/* The minimum, maximum, likely, and unlikely maximum number of bytes - of output either a formatting function or an individual directive - can result in. */ - -struct result_range -{ - /* The absolute minimum number of bytes. The result of a successful - conversion is guaranteed to be no less than this. (An erroneous - conversion can be indicated by MIN > HOST_WIDE_INT_MAX.) */ - unsigned HOST_WIDE_INT min; - /* The likely maximum result that is used in diagnostics. In most - cases MAX is the same as the worst case UNLIKELY result. */ - unsigned HOST_WIDE_INT max; - /* The likely result used to trigger diagnostics. For conversions - that result in a range of bytes [MIN, MAX], LIKELY is somewhere - in that range. */ - unsigned HOST_WIDE_INT likely; - /* In rare cases (e.g., for multibyte characters) UNLIKELY gives - the worst cases maximum result of a directive. In most cases - UNLIKELY == MAX. UNLIKELY is used to control the return value - optimization but not in diagnostics. */ - unsigned HOST_WIDE_INT unlikely; -}; - -/* Return the value of INT_MIN for the target. */ - -static inline HOST_WIDE_INT -target_int_min () -{ - return tree_to_shwi (TYPE_MIN_VALUE (integer_type_node)); -} - -/* Return the value of INT_MAX for the target. */ - -static inline unsigned HOST_WIDE_INT -target_int_max () -{ - return tree_to_uhwi (TYPE_MAX_VALUE (integer_type_node)); -} - -/* Return the value of SIZE_MAX for the target. */ - -static inline unsigned HOST_WIDE_INT -target_size_max () -{ - return tree_to_uhwi (TYPE_MAX_VALUE (size_type_node)); -} - -/* A straightforward mapping from the execution character set to the host - character set indexed by execution character. */ - -static char target_to_host_charmap[256]; - -/* Initialize a mapping from the execution character set to the host - character set. */ - -static bool -init_target_to_host_charmap () -{ - /* If the percent sign is non-zero the mapping has already been - initialized. */ - if (target_to_host_charmap['%']) - return true; - - /* Initialize the target_percent character (done elsewhere). */ - if (!init_target_chars ()) - return false; - - /* The subset of the source character set used by printf conversion - specifications (strictly speaking, not all letters are used but - they are included here for the sake of simplicity). The dollar - sign must be included even though it's not in the basic source - character set. */ - const char srcset[] = " 0123456789!\"#%&'()*+,-./:;<=>?[\\]^_{|}~$" - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - /* Set the mapping for all characters to some ordinary value (i,e., - not none used in printf conversion specifications) and overwrite - those that are used by conversion specifications with their - corresponding values. */ - memset (target_to_host_charmap + 1, '?', sizeof target_to_host_charmap - 1); - - /* Are the two sets of characters the same? */ - bool all_same_p = true; - - for (const char *pc = srcset; *pc; ++pc) - { - /* Slice off the high end bits in case target characters are - signed. All values are expected to be non-nul, otherwise - there's a problem. */ - if (unsigned char tc = lang_hooks.to_target_charset (*pc)) - { - target_to_host_charmap[tc] = *pc; - if (tc != *pc) - all_same_p = false; - } - else - return false; - - } - - /* Set the first element to a non-zero value if the mapping - is 1-to-1, otherwise leave it clear (NUL is assumed to be - the same in both character sets). */ - target_to_host_charmap[0] = all_same_p; - - return true; -} - -/* Return the host source character corresponding to the character - CH in the execution character set if one exists, or some innocuous - (non-special, non-nul) source character otherwise. */ - -static inline unsigned char -target_to_host (unsigned char ch) -{ - return target_to_host_charmap[ch]; -} - -/* Convert an initial substring of the string TARGSTR consisting of - characters in the execution character set into a string in the - source character set on the host and store up to HOSTSZ characters - in the buffer pointed to by HOSTR. Return HOSTR. */ - -static const char* -target_to_host (char *hostr, size_t hostsz, const char *targstr) -{ - /* Make sure the buffer is reasonably big. */ - gcc_assert (hostsz > 4); - - /* The interesting subset of source and execution characters are - the same so no conversion is necessary. However, truncate - overlong strings just like the translated strings are. */ - if (target_to_host_charmap['\0'] == 1) - { - size_t len = strlen (targstr); - if (len >= hostsz) - { - memcpy (hostr, targstr, hostsz - 4); - strcpy (hostr + hostsz - 4, "..."); - } - else - memcpy (hostr, targstr, len + 1); - return hostr; - } - - /* Convert the initial substring of TARGSTR to the corresponding - characters in the host set, appending "..." if TARGSTR is too - long to fit. Using the static buffer assumes the function is - not called in between sequence points (which it isn't). */ - for (char *ph = hostr; ; ++targstr) - { - *ph++ = target_to_host (*targstr); - if (!*targstr) - break; - - if (size_t (ph - hostr) == hostsz) - { - strcpy (ph - 4, "..."); - break; - } - } - - return hostr; -} - -/* Convert the sequence of decimal digits in the execution character - starting at *PS to a HOST_WIDE_INT, analogously to strtol. Return - the result and set *PS to one past the last converted character. - On range error set ERANGE to the digit that caused it. */ - -static inline HOST_WIDE_INT -target_strtowi (const char **ps, const char **erange) -{ - unsigned HOST_WIDE_INT val = 0; - for ( ; ; ++*ps) - { - unsigned char c = target_to_host (**ps); - if (ISDIGIT (c)) - { - c -= '0'; - - /* Check for overflow. */ - if (val > ((unsigned HOST_WIDE_INT) HOST_WIDE_INT_MAX - c) / 10LU) - { - val = HOST_WIDE_INT_MAX; - *erange = *ps; - - /* Skip the remaining digits. */ - do - c = target_to_host (*++*ps); - while (ISDIGIT (c)); - break; - } - else - val = val * 10 + c; - } - else - break; - } - - return val; -} - -/* Given FORMAT, set *PLOC to the source location of the format string - and return the format string if it is known or null otherwise. */ - -static const char* -get_format_string (tree format, location_t *ploc) -{ - *ploc = EXPR_LOC_OR_LOC (format, input_location); - - return c_getstr (format); -} - -/* For convenience and brevity, shorter named entrypoints of - format_string_diagnostic_t::emit_warning_va and - format_string_diagnostic_t::emit_warning_n_va. - These have to be functions with the attribute so that exgettext - works properly. */ - -static bool -ATTRIBUTE_GCC_DIAG (5, 6) -fmtwarn (const substring_loc &fmt_loc, location_t param_loc, - const char *corrected_substring, opt_code opt, - const char *gmsgid, ...) -{ - format_string_diagnostic_t diag (fmt_loc, NULL, param_loc, NULL, - corrected_substring); - va_list ap; - va_start (ap, gmsgid); - bool warned = diag.emit_warning_va (opt, gmsgid, &ap); - va_end (ap); - - return warned; -} - -static bool -ATTRIBUTE_GCC_DIAG (6, 8) ATTRIBUTE_GCC_DIAG (7, 8) -fmtwarn_n (const substring_loc &fmt_loc, location_t param_loc, - const char *corrected_substring, opt_code opt, - unsigned HOST_WIDE_INT n, - const char *singular_gmsgid, const char *plural_gmsgid, ...) -{ - format_string_diagnostic_t diag (fmt_loc, NULL, param_loc, NULL, - corrected_substring); - va_list ap; - va_start (ap, plural_gmsgid); - bool warned = diag.emit_warning_n_va (opt, n, singular_gmsgid, plural_gmsgid, - &ap); - va_end (ap); - - return warned; -} - -/* Format length modifiers. */ - -enum format_lengths -{ - FMT_LEN_none, - FMT_LEN_hh, // char argument - FMT_LEN_h, // short - FMT_LEN_l, // long - FMT_LEN_ll, // long long - FMT_LEN_L, // long double (and GNU long long) - FMT_LEN_z, // size_t - FMT_LEN_t, // ptrdiff_t - FMT_LEN_j // intmax_t -}; - - -/* Description of the result of conversion either of a single directive - or the whole format string. */ - -class fmtresult -{ -public: - /* Construct a FMTRESULT object with all counters initialized - to MIN. KNOWNRANGE is set when MIN is valid. */ - fmtresult (unsigned HOST_WIDE_INT min = HOST_WIDE_INT_MAX) - : argmin (), argmax (), dst_offset (HOST_WIDE_INT_MIN), nonstr (), - knownrange (min < HOST_WIDE_INT_MAX), - mayfail (), nullp () - { - range.min = min; - range.max = min; - range.likely = min; - range.unlikely = min; - } - - /* Construct a FMTRESULT object with MIN, MAX, and LIKELY counters. - KNOWNRANGE is set when both MIN and MAX are valid. */ - fmtresult (unsigned HOST_WIDE_INT min, unsigned HOST_WIDE_INT max, - unsigned HOST_WIDE_INT likely = HOST_WIDE_INT_MAX) - : argmin (), argmax (), dst_offset (HOST_WIDE_INT_MIN), nonstr (), - knownrange (min < HOST_WIDE_INT_MAX && max < HOST_WIDE_INT_MAX), - mayfail (), nullp () - { - range.min = min; - range.max = max; - range.likely = max < likely ? min : likely; - range.unlikely = max; - } - - /* Adjust result upward to reflect the RANGE of values the specified - width or precision is known to be in. */ - fmtresult& adjust_for_width_or_precision (const HOST_WIDE_INT[2], - tree = NULL_TREE, - unsigned = 0, unsigned = 0); - - /* Return the maximum number of decimal digits a value of TYPE - formats as on output. */ - static unsigned type_max_digits (tree, int); - - /* The range a directive's argument is in. */ - tree argmin, argmax; - - /* The starting offset into the destination of the formatted function - call of the %s argument that points into (aliases with) the same - destination array. */ - HOST_WIDE_INT dst_offset; - - /* The minimum and maximum number of bytes that a directive - results in on output for an argument in the range above. */ - result_range range; - - /* Non-nul when the argument of a string directive is not a nul - terminated string. */ - tree nonstr; - - /* True when the range above is obtained from a known value of - a directive's argument or its bounds and not the result of - heuristics that depend on warning levels. */ - bool knownrange; - - /* True for a directive that may fail (such as wide character - directives). */ - bool mayfail; - - /* True when the argument is a null pointer. */ - bool nullp; -}; - -/* Adjust result upward to reflect the range ADJUST of values the - specified width or precision is known to be in. When non-null, - TYPE denotes the type of the directive whose result is being - adjusted, BASE gives the base of the directive (octal, decimal, - or hex), and ADJ denotes the additional adjustment to the LIKELY - counter that may need to be added when ADJUST is a range. */ - -fmtresult& -fmtresult::adjust_for_width_or_precision (const HOST_WIDE_INT adjust[2], - tree type /* = NULL_TREE */, - unsigned base /* = 0 */, - unsigned adj /* = 0 */) -{ - bool minadjusted = false; - - /* Adjust the minimum and likely counters. */ - if (adjust[0] >= 0) - { - if (range.min < (unsigned HOST_WIDE_INT)adjust[0]) - { - range.min = adjust[0]; - minadjusted = true; - } - - /* Adjust the likely counter. */ - if (range.likely < range.min) - range.likely = range.min; - } - else if (adjust[0] == target_int_min () - && (unsigned HOST_WIDE_INT)adjust[1] == target_int_max ()) - knownrange = false; - - /* Adjust the maximum counter. */ - if (adjust[1] > 0) - { - if (range.max < (unsigned HOST_WIDE_INT)adjust[1]) - { - range.max = adjust[1]; - - /* Set KNOWNRANGE if both the minimum and maximum have been - adjusted. Otherwise leave it at what it was before. */ - knownrange = minadjusted; - } - } - - if (warn_level > 1 && type) - { - /* For large non-constant width or precision whose range spans - the maximum number of digits produced by the directive for - any argument, set the likely number of bytes to be at most - the number digits plus other adjustment determined by the - caller (one for sign or two for the hexadecimal "0x" - prefix). */ - unsigned dirdigs = type_max_digits (type, base); - if (adjust[0] < dirdigs && dirdigs < adjust[1] - && range.likely < dirdigs) - range.likely = dirdigs + adj; - } - else if (range.likely < (range.min ? range.min : 1)) - { - /* Conservatively, set LIKELY to at least MIN but no less than - 1 unless MAX is zero. */ - range.likely = (range.min - ? range.min - : range.max && (range.max < HOST_WIDE_INT_MAX - || warn_level > 1) ? 1 : 0); - } - - /* Finally adjust the unlikely counter to be at least as large as - the maximum. */ - if (range.unlikely < range.max) - range.unlikely = range.max; - - return *this; -} - -/* Return the maximum number of digits a value of TYPE formats in - BASE on output, not counting base prefix . */ - -unsigned -fmtresult::type_max_digits (tree type, int base) -{ - unsigned prec = TYPE_PRECISION (type); - switch (base) - { - case 8: - return (prec + 2) / 3; - case 10: - /* Decimal approximation: yields 3, 5, 10, and 20 for precision - of 8, 16, 32, and 64 bits. */ - return prec * 301 / 1000 + 1; - case 16: - return prec / 4; - } - - gcc_unreachable (); -} - -static bool -get_int_range (tree, gimple *, HOST_WIDE_INT *, HOST_WIDE_INT *, - bool, HOST_WIDE_INT, range_query *); - -struct call_info; - -/* Description of a format directive. A directive is either a plain - string or a conversion specification that starts with '%'. */ - -struct directive -{ - directive (const call_info *inf, unsigned dno) - : info (inf), dirno (dno), argno (), beg (), len (), flags (), - width (), prec (), modifier (), specifier (), arg (), fmtfunc () - { } - - /* Reference to the info structure describing the call that this - directive is a part of. */ - const call_info *info; - - /* The 1-based directive number (for debugging). */ - unsigned dirno; - - /* The zero-based argument number of the directive's argument ARG in - the function's argument list. */ - unsigned argno; - - /* The first character of the directive and its length. */ - const char *beg; - size_t len; - - /* A bitmap of flags, one for each character. */ - unsigned flags[256 / sizeof (int)]; - - /* The range of values of the specified width, or -1 if not specified. */ - HOST_WIDE_INT width[2]; - /* The range of values of the specified precision, or -1 if not - specified. */ - HOST_WIDE_INT prec[2]; - - /* Length modifier. */ - format_lengths modifier; - - /* Format specifier character. */ - char specifier; - - /* The argument of the directive or null when the directive doesn't - take one or when none is available (such as for vararg functions). */ - tree arg; - - /* Format conversion function that given a directive and an argument - returns the formatting result. */ - fmtresult (*fmtfunc) (const directive &, tree, range_query *); - - /* Return True when the format flag CHR has been used. */ - bool get_flag (char chr) const - { - unsigned char c = chr & 0xff; - return (flags[c / (CHAR_BIT * sizeof *flags)] - & (1U << (c % (CHAR_BIT * sizeof *flags)))); - } - - /* Make a record of the format flag CHR having been used. */ - void set_flag (char chr) - { - unsigned char c = chr & 0xff; - flags[c / (CHAR_BIT * sizeof *flags)] - |= (1U << (c % (CHAR_BIT * sizeof *flags))); - } - - /* Reset the format flag CHR. */ - void clear_flag (char chr) - { - unsigned char c = chr & 0xff; - flags[c / (CHAR_BIT * sizeof *flags)] - &= ~(1U << (c % (CHAR_BIT * sizeof *flags))); - } - - /* Set both bounds of the width range to VAL. */ - void set_width (HOST_WIDE_INT val) - { - width[0] = width[1] = val; - } - - /* Set the width range according to ARG, with both bounds being - no less than 0. For a constant ARG set both bounds to its value - or 0, whichever is greater. For a non-constant ARG in some range - set width to its range adjusting each bound to -1 if it's less. - For an indeterminate ARG set width to [0, INT_MAX]. */ - void set_width (tree arg, range_query *); - - /* Set both bounds of the precision range to VAL. */ - void set_precision (HOST_WIDE_INT val) - { - prec[0] = prec[1] = val; - } - - /* Set the precision range according to ARG, with both bounds being - no less than -1. For a constant ARG set both bounds to its value - or -1 whichever is greater. For a non-constant ARG in some range - set precision to its range adjusting each bound to -1 if it's less. - For an indeterminate ARG set precision to [-1, INT_MAX]. */ - void set_precision (tree arg, range_query *query); - - /* Return true if both width and precision are known to be - either constant or in some range, false otherwise. */ - bool known_width_and_precision () const - { - return ((width[1] < 0 - || (unsigned HOST_WIDE_INT)width[1] <= target_int_max ()) - && (prec[1] < 0 - || (unsigned HOST_WIDE_INT)prec[1] < target_int_max ())); - } -}; - -/* The result of a call to a formatted function. */ - -struct format_result -{ - format_result () - : range (), aliases (), alias_count (), knownrange (), posunder4k (), - floating (), warned () { /* No-op. */ } - - ~format_result () - { - XDELETEVEC (aliases); - } - - /* Range of characters written by the formatted function. - Setting the minimum to HOST_WIDE_INT_MAX disables all - length tracking for the remainder of the format string. */ - result_range range; - - struct alias_info - { - directive dir; /* The directive that aliases the destination. */ - HOST_WIDE_INT offset; /* The offset at which it aliases it. */ - result_range range; /* The raw result of the directive. */ - }; - - /* An array of directives whose pointer argument aliases a part - of the destination object of the formatted function. */ - alias_info *aliases; - unsigned alias_count; - - /* True when the range above is obtained from known values of - directive arguments, or bounds on the amount of output such - as width and precision, and not the result of heuristics that - depend on warning levels. It's used to issue stricter diagnostics - in cases where strings of unknown lengths are bounded by the arrays - they are determined to refer to. KNOWNRANGE must not be used for - the return value optimization. */ - bool knownrange; - - /* True if no individual directive could fail or result in more than - 4095 bytes of output (the total NUMBER_CHARS_{MIN,MAX} might be - greater). Implementations are not required to handle directives - that produce more than 4K bytes (leading to undefined behavior) - and so when one is found it disables the return value optimization. - Similarly, directives that can fail (such as wide character - directives) disable the optimization. */ - bool posunder4k; - - /* True when a floating point directive has been seen in the format - string. */ - bool floating; - - /* True when an intermediate result has caused a warning. Used to - avoid issuing duplicate warnings while finishing the processing - of a call. WARNED also disables the return value optimization. */ - bool warned; - - /* Preincrement the number of output characters by 1. */ - format_result& operator++ () - { - return *this += 1; - } - - /* Postincrement the number of output characters by 1. */ - format_result operator++ (int) - { - format_result prev (*this); - *this += 1; - return prev; - } - - /* Increment the number of output characters by N. */ - format_result& operator+= (unsigned HOST_WIDE_INT); - - /* Add a directive to the sequence of those with potentially aliasing - arguments. */ - void append_alias (const directive &, HOST_WIDE_INT, const result_range &); - -private: - /* Not copyable or assignable. */ - format_result (format_result&); - void operator= (format_result&); -}; - -format_result& -format_result::operator+= (unsigned HOST_WIDE_INT n) -{ - gcc_assert (n < HOST_WIDE_INT_MAX); - - if (range.min < HOST_WIDE_INT_MAX) - range.min += n; - - if (range.max < HOST_WIDE_INT_MAX) - range.max += n; - - if (range.likely < HOST_WIDE_INT_MAX) - range.likely += n; - - if (range.unlikely < HOST_WIDE_INT_MAX) - range.unlikely += n; - - return *this; -} - -void -format_result::append_alias (const directive &d, HOST_WIDE_INT off, - const result_range &resrng) -{ - unsigned cnt = alias_count + 1; - alias_info *ar = XNEWVEC (alias_info, cnt); - - for (unsigned i = 0; i != alias_count; ++i) - ar[i] = aliases[i]; - - ar[alias_count].dir = d; - ar[alias_count].offset = off; - ar[alias_count].range = resrng; - - XDELETEVEC (aliases); - - alias_count = cnt; - aliases = ar; -} - -/* Return the logarithm of X in BASE. */ - -static int -ilog (unsigned HOST_WIDE_INT x, int base) -{ - int res = 0; - do - { - ++res; - x /= base; - } while (x); - return res; -} - -/* Return the number of bytes resulting from converting into a string - the INTEGER_CST tree node X in BASE with a minimum of PREC digits. - PLUS indicates whether 1 for a plus sign should be added for positive - numbers, and PREFIX whether the length of an octal ('O') or hexadecimal - ('0x') prefix should be added for nonzero numbers. Return -1 if X cannot - be represented. */ - -static HOST_WIDE_INT -tree_digits (tree x, int base, HOST_WIDE_INT prec, bool plus, bool prefix) -{ - unsigned HOST_WIDE_INT absval; - - HOST_WIDE_INT res; - - if (TYPE_UNSIGNED (TREE_TYPE (x))) - { - if (tree_fits_uhwi_p (x)) - { - absval = tree_to_uhwi (x); - res = plus; - } - else - return -1; - } - else - { - if (tree_fits_shwi_p (x)) - { - HOST_WIDE_INT i = tree_to_shwi (x); - if (HOST_WIDE_INT_MIN == i) - { - /* Avoid undefined behavior due to negating a minimum. */ - absval = HOST_WIDE_INT_MAX; - res = 1; - } - else if (i < 0) - { - absval = -i; - res = 1; - } - else - { - absval = i; - res = plus; - } - } - else - return -1; - } - - int ndigs = ilog (absval, base); - - res += prec < ndigs ? ndigs : prec; - - /* Adjust a non-zero value for the base prefix, either hexadecimal, - or, unless precision has resulted in a leading zero, also octal. */ - if (prefix && absval && (base == 16 || prec <= ndigs)) - { - if (base == 8) - res += 1; - else if (base == 16) - res += 2; - } - - return res; -} - -/* Description of a call to a formatted function. */ - -struct call_info -{ - /* Function call statement. */ - gimple *callstmt; - - /* Function called. */ - tree func; - - /* Called built-in function code. */ - built_in_function fncode; - - /* The "origin" of the destination pointer argument, which is either - the DECL of the destination buffer being written into or a pointer - that points to it, plus some offset. */ - tree dst_origin; - - /* For a destination pointing to a struct array member, the offset of - the member. */ - HOST_WIDE_INT dst_field; - - /* The offset into the destination buffer. */ - HOST_WIDE_INT dst_offset; - - /* Format argument and format string extracted from it. */ - tree format; - const char *fmtstr; - - /* The location of the format argument. */ - location_t fmtloc; - - /* The destination object size for __builtin___xxx_chk functions - typically determined by __builtin_object_size, or -1 if unknown. */ - unsigned HOST_WIDE_INT objsize; - - /* Number of the first variable argument. */ - unsigned HOST_WIDE_INT argidx; - - /* True for functions like snprintf that specify the size of - the destination, false for others like sprintf that don't. */ - bool bounded; - - /* True for bounded functions like snprintf that specify a zero-size - buffer as a request to compute the size of output without actually - writing any. NOWRITE is cleared in response to the %n directive - which has side-effects similar to writing output. */ - bool nowrite; - - /* Return true if the called function's return value is used. */ - bool retval_used () const - { - return gimple_get_lhs (callstmt); - } - - /* Return the warning option corresponding to the called function. */ - opt_code warnopt () const - { - return bounded ? OPT_Wformat_truncation_ : OPT_Wformat_overflow_; - } - - /* Return true for calls to file formatted functions. */ - bool is_file_func () const - { - return (fncode == BUILT_IN_FPRINTF - || fncode == BUILT_IN_FPRINTF_CHK - || fncode == BUILT_IN_FPRINTF_UNLOCKED - || fncode == BUILT_IN_VFPRINTF - || fncode == BUILT_IN_VFPRINTF_CHK); - } - - /* Return true for calls to string formatted functions. */ - bool is_string_func () const - { - return (fncode == BUILT_IN_SPRINTF - || fncode == BUILT_IN_SPRINTF_CHK - || fncode == BUILT_IN_SNPRINTF - || fncode == BUILT_IN_SNPRINTF_CHK - || fncode == BUILT_IN_VSPRINTF - || fncode == BUILT_IN_VSPRINTF_CHK - || fncode == BUILT_IN_VSNPRINTF - || fncode == BUILT_IN_VSNPRINTF_CHK); - } -}; - -void -directive::set_width (tree arg, range_query *query) -{ - get_int_range (arg, info->callstmt, width, width + 1, true, 0, query); -} - -void -directive::set_precision (tree arg, range_query *query) -{ - get_int_range (arg, info->callstmt, prec, prec + 1, false, -1, query); -} - -/* Return the result of formatting a no-op directive (such as '%n'). */ - -static fmtresult -format_none (const directive &, tree, range_query *) -{ - fmtresult res (0); - return res; -} - -/* Return the result of formatting the '%%' directive. */ - -static fmtresult -format_percent (const directive &, tree, range_query *) -{ - fmtresult res (1); - return res; -} - - -/* Compute intmax_type_node and uintmax_type_node similarly to how - tree.c builds size_type_node. */ - -static void -build_intmax_type_nodes (tree *pintmax, tree *puintmax) -{ - if (strcmp (UINTMAX_TYPE, "unsigned int") == 0) - { - *pintmax = integer_type_node; - *puintmax = unsigned_type_node; - } - else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0) - { - *pintmax = long_integer_type_node; - *puintmax = long_unsigned_type_node; - } - else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0) - { - *pintmax = long_long_integer_type_node; - *puintmax = long_long_unsigned_type_node; - } - else - { - for (int i = 0; i < NUM_INT_N_ENTS; i++) - if (int_n_enabled_p[i]) - { - char name[50], altname[50]; - sprintf (name, "__int%d unsigned", int_n_data[i].bitsize); - sprintf (altname, "__int%d__ unsigned", int_n_data[i].bitsize); - - if (strcmp (name, UINTMAX_TYPE) == 0 - || strcmp (altname, UINTMAX_TYPE) == 0) - { - *pintmax = int_n_trees[i].signed_type; - *puintmax = int_n_trees[i].unsigned_type; - return; - } - } - gcc_unreachable (); - } -} - -/* Determine the range [*PMIN, *PMAX] that the expression ARG is - in and that is representable in type int. - Return true when the range is a subrange of that of int. - When ARG is null it is as if it had the full range of int. - When ABSOLUTE is true the range reflects the absolute value of - the argument. When ABSOLUTE is false, negative bounds of - the determined range are replaced with NEGBOUND. */ - -static bool -get_int_range (tree arg, gimple *stmt, - HOST_WIDE_INT *pmin, HOST_WIDE_INT *pmax, - bool absolute, HOST_WIDE_INT negbound, - range_query *query) -{ - /* The type of the result. */ - const_tree type = integer_type_node; - - bool knownrange = false; - - if (!arg) - { - *pmin = tree_to_shwi (TYPE_MIN_VALUE (type)); - *pmax = tree_to_shwi (TYPE_MAX_VALUE (type)); - } - else if (TREE_CODE (arg) == INTEGER_CST - && TYPE_PRECISION (TREE_TYPE (arg)) <= TYPE_PRECISION (type)) - { - /* For a constant argument return its value adjusted as specified - by NEGATIVE and NEGBOUND and return true to indicate that the - result is known. */ - *pmin = tree_fits_shwi_p (arg) ? tree_to_shwi (arg) : tree_to_uhwi (arg); - *pmax = *pmin; - knownrange = true; - } - else - { - /* True if the argument's range cannot be determined. */ - bool unknown = true; - - tree argtype = TREE_TYPE (arg); - - /* Ignore invalid arguments with greater precision that that - of the expected type (e.g., in sprintf("%*i", 12LL, i)). - They will have been detected and diagnosed by -Wformat and - so it's not important to complicate this code to try to deal - with them again. */ - if (TREE_CODE (arg) == SSA_NAME - && INTEGRAL_TYPE_P (argtype) - && TYPE_PRECISION (argtype) <= TYPE_PRECISION (type)) - { - /* Try to determine the range of values of the integer argument. */ - value_range vr; - query->range_of_expr (vr, arg, stmt); - - if (!vr.undefined_p () && !vr.varying_p ()) - { - HOST_WIDE_INT type_min - = (TYPE_UNSIGNED (argtype) - ? tree_to_uhwi (TYPE_MIN_VALUE (argtype)) - : tree_to_shwi (TYPE_MIN_VALUE (argtype))); - - HOST_WIDE_INT type_max = tree_to_uhwi (TYPE_MAX_VALUE (argtype)); - - tree type = TREE_TYPE (arg); - tree tmin = wide_int_to_tree (type, vr.lower_bound ()); - tree tmax = wide_int_to_tree (type, vr.upper_bound ()); - *pmin = TREE_INT_CST_LOW (tmin); - *pmax = TREE_INT_CST_LOW (tmax); - - if (*pmin < *pmax) - { - /* Return true if the adjusted range is a subrange of - the full range of the argument's type. *PMAX may - be less than *PMIN when the argument is unsigned - and its upper bound is in excess of TYPE_MAX. In - that (invalid) case disregard the range and use that - of the expected type instead. */ - knownrange = type_min < *pmin || *pmax < type_max; - - unknown = false; - } - } - } - - /* Handle an argument with an unknown range as if none had been - provided. */ - if (unknown) - return get_int_range (NULL_TREE, NULL, pmin, pmax, absolute, - negbound, query); - } - - /* Adjust each bound as specified by ABSOLUTE and NEGBOUND. */ - if (absolute) - { - if (*pmin < 0) - { - if (*pmin == *pmax) - *pmin = *pmax = -*pmin; - else - { - /* Make sure signed overlow is avoided. */ - gcc_assert (*pmin != HOST_WIDE_INT_MIN); - - HOST_WIDE_INT tmp = -*pmin; - *pmin = 0; - if (*pmax < tmp) - *pmax = tmp; - } - } - } - else if (*pmin < negbound) - *pmin = negbound; - - return knownrange; -} - -/* With the range [*ARGMIN, *ARGMAX] of an integer directive's actual - argument, due to the conversion from either *ARGMIN or *ARGMAX to - the type of the directive's formal argument it's possible for both - to result in the same number of bytes or a range of bytes that's - less than the number of bytes that would result from formatting - some other value in the range [*ARGMIN, *ARGMAX]. This can be - determined by checking for the actual argument being in the range - of the type of the directive. If it isn't it must be assumed to - take on the full range of the directive's type. - Return true when the range has been adjusted to the full range - of DIRTYPE, and false otherwise. */ - -static bool -adjust_range_for_overflow (tree dirtype, tree *argmin, tree *argmax) -{ - tree argtype = TREE_TYPE (*argmin); - unsigned argprec = TYPE_PRECISION (argtype); - unsigned dirprec = TYPE_PRECISION (dirtype); - - /* If the actual argument and the directive's argument have the same - precision and sign there can be no overflow and so there is nothing - to adjust. */ - if (argprec == dirprec && TYPE_SIGN (argtype) == TYPE_SIGN (dirtype)) - return false; - - /* The logic below was inspired/lifted from the CONVERT_EXPR_CODE_P - branch in the extract_range_from_unary_expr function in tree-vrp.c. */ - - if (TREE_CODE (*argmin) == INTEGER_CST - && TREE_CODE (*argmax) == INTEGER_CST - && (dirprec >= argprec - || integer_zerop (int_const_binop (RSHIFT_EXPR, - int_const_binop (MINUS_EXPR, - *argmax, - *argmin), - size_int (dirprec))))) - { - *argmin = force_fit_type (dirtype, wi::to_widest (*argmin), 0, false); - *argmax = force_fit_type (dirtype, wi::to_widest (*argmax), 0, false); - - /* If *ARGMIN is still less than *ARGMAX the conversion above - is safe. Otherwise, it has overflowed and would be unsafe. */ - if (tree_int_cst_le (*argmin, *argmax)) - return false; - } - - *argmin = TYPE_MIN_VALUE (dirtype); - *argmax = TYPE_MAX_VALUE (dirtype); - return true; -} - -/* Return a range representing the minimum and maximum number of bytes - that the format directive DIR will output for any argument given - the WIDTH and PRECISION (extracted from DIR). This function is - used when the directive argument or its value isn't known. */ - -static fmtresult -format_integer (const directive &dir, tree arg, range_query *query) -{ - tree intmax_type_node; - tree uintmax_type_node; - - /* Base to format the number in. */ - int base; - - /* True when a conversion is preceded by a prefix indicating the base - of the argument (octal or hexadecimal). */ - bool maybebase = dir.get_flag ('#'); - - /* True when a signed conversion is preceded by a sign or space. */ - bool maybesign = false; - - /* True for signed conversions (i.e., 'd' and 'i'). */ - bool sign = false; - - switch (dir.specifier) - { - case 'd': - case 'i': - /* Space and '+' are only meaningful for signed conversions. */ - maybesign = dir.get_flag (' ') | dir.get_flag ('+'); - sign = true; - base = 10; - break; - case 'u': - base = 10; - break; - case 'o': - base = 8; - break; - case 'X': - case 'x': - base = 16; - break; - default: - gcc_unreachable (); - } - - /* The type of the "formal" argument expected by the directive. */ - tree dirtype = NULL_TREE; - - /* Determine the expected type of the argument from the length - modifier. */ - switch (dir.modifier) - { - case FMT_LEN_none: - if (dir.specifier == 'p') - dirtype = ptr_type_node; - else - dirtype = sign ? integer_type_node : unsigned_type_node; - break; - - case FMT_LEN_h: - dirtype = sign ? short_integer_type_node : short_unsigned_type_node; - break; - - case FMT_LEN_hh: - dirtype = sign ? signed_char_type_node : unsigned_char_type_node; - break; - - case FMT_LEN_l: - dirtype = sign ? long_integer_type_node : long_unsigned_type_node; - break; - - case FMT_LEN_L: - case FMT_LEN_ll: - dirtype = (sign - ? long_long_integer_type_node - : long_long_unsigned_type_node); - break; - - case FMT_LEN_z: - dirtype = signed_or_unsigned_type_for (!sign, size_type_node); - break; - - case FMT_LEN_t: - dirtype = signed_or_unsigned_type_for (!sign, ptrdiff_type_node); - break; - - case FMT_LEN_j: - build_intmax_type_nodes (&intmax_type_node, &uintmax_type_node); - dirtype = sign ? intmax_type_node : uintmax_type_node; - break; - - default: - return fmtresult (); - } - - /* The type of the argument to the directive, either deduced from - the actual non-constant argument if one is known, or from - the directive itself when none has been provided because it's - a va_list. */ - tree argtype = NULL_TREE; - - if (!arg) - { - /* When the argument has not been provided, use the type of - the directive's argument as an approximation. This will - result in false positives for directives like %i with - arguments with smaller precision (such as short or char). */ - argtype = dirtype; - } - else if (TREE_CODE (arg) == INTEGER_CST) - { - /* When a constant argument has been provided use its value - rather than type to determine the length of the output. */ - fmtresult res; - - if ((dir.prec[0] <= 0 && dir.prec[1] >= 0) && integer_zerop (arg)) - { - /* As a special case, a precision of zero with a zero argument - results in zero bytes except in base 8 when the '#' flag is - specified, and for signed conversions in base 8 and 10 when - either the space or '+' flag has been specified and it results - in just one byte (with width having the normal effect). This - must extend to the case of a specified precision with - an unknown value because it can be zero. */ - res.range.min = ((base == 8 && dir.get_flag ('#')) || maybesign); - if (res.range.min == 0 && dir.prec[0] != dir.prec[1]) - { - res.range.max = 1; - res.range.likely = 1; - } - else - { - res.range.max = res.range.min; - res.range.likely = res.range.min; - } - } - else - { - /* Convert the argument to the type of the directive. */ - arg = fold_convert (dirtype, arg); - - res.range.min = tree_digits (arg, base, dir.prec[0], - maybesign, maybebase); - if (dir.prec[0] == dir.prec[1]) - res.range.max = res.range.min; - else - res.range.max = tree_digits (arg, base, dir.prec[1], - maybesign, maybebase); - res.range.likely = res.range.min; - res.knownrange = true; - } - - res.range.unlikely = res.range.max; - - /* Bump up the counters if WIDTH is greater than LEN. */ - res.adjust_for_width_or_precision (dir.width, dirtype, base, - (sign | maybebase) + (base == 16)); - /* Bump up the counters again if PRECision is greater still. */ - res.adjust_for_width_or_precision (dir.prec, dirtype, base, - (sign | maybebase) + (base == 16)); - - return res; - } - else if (INTEGRAL_TYPE_P (TREE_TYPE (arg)) - || TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE) - /* Determine the type of the provided non-constant argument. */ - argtype = TREE_TYPE (arg); - else - /* Don't bother with invalid arguments since they likely would - have already been diagnosed, and disable any further checking - of the format string by returning [-1, -1]. */ - return fmtresult (); - - fmtresult res; - - /* Using either the range the non-constant argument is in, or its - type (either "formal" or actual), create a range of values that - constrain the length of output given the warning level. */ - tree argmin = NULL_TREE; - tree argmax = NULL_TREE; - - if (arg - && TREE_CODE (arg) == SSA_NAME - && INTEGRAL_TYPE_P (argtype)) - { - /* Try to determine the range of values of the integer argument - (range information is not available for pointers). */ - value_range vr; - query->range_of_expr (vr, arg, dir.info->callstmt); - - if (!vr.varying_p () && !vr.undefined_p ()) - { - argmin = wide_int_to_tree (TREE_TYPE (arg), vr.lower_bound ()); - argmax = wide_int_to_tree (TREE_TYPE (arg), vr.upper_bound ()); - - /* Set KNOWNRANGE if the argument is in a known subrange - of the directive's type and neither width nor precision - is unknown. (KNOWNRANGE may be reset below). */ - res.knownrange - = ((!tree_int_cst_equal (TYPE_MIN_VALUE (dirtype), argmin) - || !tree_int_cst_equal (TYPE_MAX_VALUE (dirtype), argmax)) - && dir.known_width_and_precision ()); - - res.argmin = argmin; - res.argmax = argmax; - } - else - { - /* The argument here may be the result of promoting the actual - argument to int. Try to determine the type of the actual - argument before promotion and narrow down its range that - way. */ - gimple *def = SSA_NAME_DEF_STMT (arg); - if (is_gimple_assign (def)) - { - tree_code code = gimple_assign_rhs_code (def); - if (code == INTEGER_CST) - { - arg = gimple_assign_rhs1 (def); - return format_integer (dir, arg, query); - } - - if (code == NOP_EXPR) - { - tree type = TREE_TYPE (gimple_assign_rhs1 (def)); - if (INTEGRAL_TYPE_P (type) - || TREE_CODE (type) == POINTER_TYPE) - argtype = type; - } - } - } - } - - if (!argmin) - { - if (TREE_CODE (argtype) == POINTER_TYPE) - { - argmin = build_int_cst (pointer_sized_int_node, 0); - argmax = build_all_ones_cst (pointer_sized_int_node); - } - else - { - argmin = TYPE_MIN_VALUE (argtype); - argmax = TYPE_MAX_VALUE (argtype); - } - } - - /* Clear KNOWNRANGE if the range has been adjusted to the maximum - of the directive. If it has been cleared then since ARGMIN and/or - ARGMAX have been adjusted also adjust the corresponding ARGMIN and - ARGMAX in the result to include in diagnostics. */ - if (adjust_range_for_overflow (dirtype, &argmin, &argmax)) - { - res.knownrange = false; - res.argmin = argmin; - res.argmax = argmax; - } - - /* Recursively compute the minimum and maximum from the known range. */ - if (TYPE_UNSIGNED (dirtype) || tree_int_cst_sgn (argmin) >= 0) - { - /* For unsigned conversions/directives or signed when - the minimum is positive, use the minimum and maximum to compute - the shortest and longest output, respectively. */ - res.range.min = format_integer (dir, argmin, query).range.min; - res.range.max = format_integer (dir, argmax, query).range.max; - } - else if (tree_int_cst_sgn (argmax) < 0) - { - /* For signed conversions/directives if maximum is negative, - use the minimum as the longest output and maximum as the - shortest output. */ - res.range.min = format_integer (dir, argmax, query).range.min; - res.range.max = format_integer (dir, argmin, query).range.max; - } - else - { - /* Otherwise, 0 is inside of the range and minimum negative. Use 0 - as the shortest output and for the longest output compute the - length of the output of both minimum and maximum and pick the - longer. */ - unsigned HOST_WIDE_INT max1 - = format_integer (dir, argmin, query).range.max; - unsigned HOST_WIDE_INT max2 - = format_integer (dir, argmax, query).range.max; - res.range.min - = format_integer (dir, integer_zero_node, query).range.min; - res.range.max = MAX (max1, max2); - } - - /* If the range is known, use the maximum as the likely length. */ - if (res.knownrange) - res.range.likely = res.range.max; - else - { - /* Otherwise, use the minimum. Except for the case where for %#x or - %#o the minimum is just for a single value in the range (0) and - for all other values it is something longer, like 0x1 or 01. - Use the length for value 1 in that case instead as the likely - length. */ - res.range.likely = res.range.min; - if (maybebase - && base != 10 - && (tree_int_cst_sgn (argmin) < 0 || tree_int_cst_sgn (argmax) > 0)) - { - if (res.range.min == 1) - res.range.likely += base == 8 ? 1 : 2; - else if (res.range.min == 2 - && base == 16 - && (dir.width[0] == 2 || dir.prec[0] == 2)) - ++res.range.likely; - } - } - - res.range.unlikely = res.range.max; - res.adjust_for_width_or_precision (dir.width, dirtype, base, - (sign | maybebase) + (base == 16)); - res.adjust_for_width_or_precision (dir.prec, dirtype, base, - (sign | maybebase) + (base == 16)); - - return res; -} - -/* Return the number of bytes that a format directive consisting of FLAGS, - PRECision, format SPECification, and MPFR rounding specifier RNDSPEC, - would result for argument X under ideal conditions (i.e., if PREC - weren't excessive). MPFR 3.1 allocates large amounts of memory for - values of PREC with large magnitude and can fail (see MPFR bug #21056). - This function works around those problems. */ - -static unsigned HOST_WIDE_INT -get_mpfr_format_length (mpfr_ptr x, const char *flags, HOST_WIDE_INT prec, - char spec, char rndspec) -{ - char fmtstr[40]; - - HOST_WIDE_INT len = strlen (flags); - - fmtstr[0] = '%'; - memcpy (fmtstr + 1, flags, len); - memcpy (fmtstr + 1 + len, ".*R", 3); - fmtstr[len + 4] = rndspec; - fmtstr[len + 5] = spec; - fmtstr[len + 6] = '\0'; - - spec = TOUPPER (spec); - if (spec == 'E' || spec == 'F') - { - /* For %e, specify the precision explicitly since mpfr_sprintf - does its own thing just to be different (see MPFR bug 21088). */ - if (prec < 0) - prec = 6; - } - else - { - /* Avoid passing negative precisions with larger magnitude to MPFR - to avoid exposing its bugs. (A negative precision is supposed - to be ignored.) */ - if (prec < 0) - prec = -1; - } - - HOST_WIDE_INT p = prec; - - if (spec == 'G' && !strchr (flags, '#')) - { - /* For G/g without the pound flag, precision gives the maximum number - of significant digits which is bounded by LDBL_MAX_10_EXP, or, for - a 128 bit IEEE extended precision, 4932. Using twice as much here - should be more than sufficient for any real format. */ - if ((IEEE_MAX_10_EXP * 2) < prec) - prec = IEEE_MAX_10_EXP * 2; - p = prec; - } - else - { - /* Cap precision arbitrarily at 1KB and add the difference - (if any) to the MPFR result. */ - if (prec > 1024) - p = 1024; - } - - len = mpfr_snprintf (NULL, 0, fmtstr, (int)p, x); - - /* Handle the unlikely (impossible?) error by returning more than - the maximum dictated by the function's return type. */ - if (len < 0) - return target_dir_max () + 1; - - /* Adjust the return value by the difference. */ - if (p < prec) - len += prec - p; - - return len; -} - -/* Return the number of bytes to format using the format specifier - SPEC and the precision PREC the largest value in the real floating - TYPE. */ - -static unsigned HOST_WIDE_INT -format_floating_max (tree type, char spec, HOST_WIDE_INT prec) -{ - machine_mode mode = TYPE_MODE (type); - - /* IBM Extended mode. */ - if (MODE_COMPOSITE_P (mode)) - mode = DFmode; - - /* Get the real type format description for the target. */ - const real_format *rfmt = REAL_MODE_FORMAT (mode); - REAL_VALUE_TYPE rv; - - real_maxval (&rv, 0, mode); - - /* Convert the GCC real value representation with the precision - of the real type to the mpfr_t format with the GCC default - round-to-nearest mode. */ - mpfr_t x; - mpfr_init2 (x, rfmt->p); - mpfr_from_real (x, &rv, MPFR_RNDN); - - /* Return a value one greater to account for the leading minus sign. */ - unsigned HOST_WIDE_INT r - = 1 + get_mpfr_format_length (x, "", prec, spec, 'D'); - mpfr_clear (x); - return r; -} - -/* Return a range representing the minimum and maximum number of bytes - that the directive DIR will output for any argument. PREC gives - the adjusted precision range to account for negative precisions - meaning the default 6. This function is used when the directive - argument or its value isn't known. */ - -static fmtresult -format_floating (const directive &dir, const HOST_WIDE_INT prec[2]) -{ - tree type; - - switch (dir.modifier) - { - case FMT_LEN_l: - case FMT_LEN_none: - type = double_type_node; - break; - - case FMT_LEN_L: - type = long_double_type_node; - break; - - case FMT_LEN_ll: - type = long_double_type_node; - break; - - default: - return fmtresult (); - } - - /* The minimum and maximum number of bytes produced by the directive. */ - fmtresult res; - - /* The minimum output as determined by flags. It's always at least 1. - When plus or space are set the output is preceded by either a sign - or a space. */ - unsigned flagmin = (1 /* for the first digit */ - + (dir.get_flag ('+') | dir.get_flag (' '))); - - /* The minimum is 3 for "inf" and "nan" for all specifiers, plus 1 - for the plus sign/space with the '+' and ' ' flags, respectively, - unless reduced below. */ - res.range.min = 2 + flagmin; - - /* When the pound flag is set the decimal point is included in output - regardless of precision. Whether or not a decimal point is included - otherwise depends on the specification and precision. */ - bool radix = dir.get_flag ('#'); - - switch (dir.specifier) - { - case 'A': - case 'a': - { - HOST_WIDE_INT minprec = 6 + !radix /* decimal point */; - if (dir.prec[0] <= 0) - minprec = 0; - else if (dir.prec[0] > 0) - minprec = dir.prec[0] + !radix /* decimal point */; - - res.range.likely = (2 /* 0x */ - + flagmin - + radix - + minprec - + 3 /* p+0 */); - - res.range.max = format_floating_max (type, 'a', prec[1]); - - /* The unlikely maximum accounts for the longest multibyte - decimal point character. */ - res.range.unlikely = res.range.max; - if (dir.prec[1] > 0) - res.range.unlikely += target_mb_len_max () - 1; - - break; - } - - case 'E': - case 'e': - { - /* Minimum output attributable to precision and, when it's - non-zero, decimal point. */ - HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0; - - /* The likely minimum output is "[-+]1.234567e+00" regardless - of the value of the actual argument. */ - res.range.likely = (flagmin - + radix - + minprec - + 2 /* e+ */ + 2); - - res.range.max = format_floating_max (type, 'e', prec[1]); - - /* The unlikely maximum accounts for the longest multibyte - decimal point character. */ - if (dir.prec[0] != dir.prec[1] - || dir.prec[0] == -1 || dir.prec[0] > 0) - res.range.unlikely = res.range.max + target_mb_len_max () -1; - else - res.range.unlikely = res.range.max; - break; - } - - case 'F': - case 'f': - { - /* Minimum output attributable to precision and, when it's non-zero, - decimal point. */ - HOST_WIDE_INT minprec = prec[0] ? prec[0] + !radix : 0; - - /* For finite numbers (i.e., not infinity or NaN) the lower bound - when precision isn't specified is 8 bytes ("1.23456" since - precision is taken to be 6). When precision is zero, the lower - bound is 1 byte (e.g., "1"). Otherwise, when precision is greater - than zero, then the lower bound is 2 plus precision (plus flags). - But in all cases, the lower bound is no greater than 3. */ - unsigned HOST_WIDE_INT min = flagmin + radix + minprec; - if (min < res.range.min) - res.range.min = min; - - /* Compute the upper bound for -TYPE_MAX. */ - res.range.max = format_floating_max (type, 'f', prec[1]); - - /* The minimum output with unknown precision is a single byte - (e.g., "0") but the more likely output is 3 bytes ("0.0"). */ - if (dir.prec[0] < 0 && dir.prec[1] > 0) - res.range.likely = 3; - else - res.range.likely = min; - - /* The unlikely maximum accounts for the longest multibyte - decimal point character. */ - if (dir.prec[0] != dir.prec[1] - || dir.prec[0] == -1 || dir.prec[0] > 0) - res.range.unlikely = res.range.max + target_mb_len_max () - 1; - break; - } - - case 'G': - case 'g': - { - /* The %g output depends on precision and the exponent of - the argument. Since the value of the argument isn't known - the lower bound on the range of bytes (not counting flags - or width) is 1 plus radix (i.e., either "0" or "0." for - "%g" and "%#g", respectively, with a zero argument). */ - unsigned HOST_WIDE_INT min = flagmin + radix; - if (min < res.range.min) - res.range.min = min; - - char spec = 'g'; - HOST_WIDE_INT maxprec = dir.prec[1]; - if (radix && maxprec) - { - /* When the pound flag (radix) is set, trailing zeros aren't - trimmed and so the longest output is the same as for %e, - except with precision minus 1 (as specified in C11). */ - spec = 'e'; - if (maxprec > 0) - --maxprec; - else if (maxprec < 0) - maxprec = 5; - } - else - maxprec = prec[1]; - - res.range.max = format_floating_max (type, spec, maxprec); - - /* The likely output is either the maximum computed above - minus 1 (assuming the maximum is positive) when precision - is known (or unspecified), or the same minimum as for %e - (which is computed for a non-negative argument). Unlike - for the other specifiers above the likely output isn't - the minimum because for %g that's 1 which is unlikely. */ - if (dir.prec[1] < 0 - || (unsigned HOST_WIDE_INT)dir.prec[1] < target_int_max ()) - res.range.likely = res.range.max - 1; - else - { - HOST_WIDE_INT minprec = 6 + !radix /* decimal point */; - res.range.likely = (flagmin - + radix - + minprec - + 2 /* e+ */ + 2); - } - - /* The unlikely maximum accounts for the longest multibyte - decimal point character. */ - res.range.unlikely = res.range.max + target_mb_len_max () - 1; - break; - } - - default: - return fmtresult (); - } - - /* Bump up the byte counters if WIDTH is greater. */ - res.adjust_for_width_or_precision (dir.width); - return res; -} - -/* Return a range representing the minimum and maximum number of bytes - that the directive DIR will write on output for the floating argument - ARG. */ - -static fmtresult -format_floating (const directive &dir, tree arg, range_query *) -{ - HOST_WIDE_INT prec[] = { dir.prec[0], dir.prec[1] }; - tree type = (dir.modifier == FMT_LEN_L || dir.modifier == FMT_LEN_ll - ? long_double_type_node : double_type_node); - - /* For an indeterminate precision the lower bound must be assumed - to be zero. */ - if (TOUPPER (dir.specifier) == 'A') - { - /* Get the number of fractional decimal digits needed to represent - the argument without a loss of accuracy. */ - unsigned fmtprec - = REAL_MODE_FORMAT (TYPE_MODE (type))->p; - - /* The precision of the IEEE 754 double format is 53. - The precision of all other GCC binary double formats - is 56 or less. */ - unsigned maxprec = fmtprec <= 56 ? 13 : 15; - - /* For %a, leave the minimum precision unspecified to let - MFPR trim trailing zeros (as it and many other systems - including Glibc happen to do) and set the maximum - precision to reflect what it would be with trailing zeros - present (as Solaris and derived systems do). */ - if (dir.prec[1] < 0) - { - /* Both bounds are negative implies that precision has - not been specified. */ - prec[0] = maxprec; - prec[1] = -1; - } - else if (dir.prec[0] < 0) - { - /* With a negative lower bound and a non-negative upper - bound set the minimum precision to zero and the maximum - to the greater of the maximum precision (i.e., with - trailing zeros present) and the specified upper bound. */ - prec[0] = 0; - prec[1] = dir.prec[1] < maxprec ? maxprec : dir.prec[1]; - } - } - else if (dir.prec[0] < 0) - { - if (dir.prec[1] < 0) - { - /* A precision in a strictly negative range is ignored and - the default of 6 is used instead. */ - prec[0] = prec[1] = 6; - } - else - { - /* For a precision in a partly negative range, the lower bound - must be assumed to be zero and the new upper bound is the - greater of 6 (the default precision used when the specified - precision is negative) and the upper bound of the specified - range. */ - prec[0] = 0; - prec[1] = dir.prec[1] < 6 ? 6 : dir.prec[1]; - } - } - - if (!arg - || TREE_CODE (arg) != REAL_CST - || !useless_type_conversion_p (type, TREE_TYPE (arg))) - return format_floating (dir, prec); - - /* The minimum and maximum number of bytes produced by the directive. */ - fmtresult res; - - /* Get the real type format description for the target. */ - const REAL_VALUE_TYPE *rvp = TREE_REAL_CST_PTR (arg); - const real_format *rfmt = REAL_MODE_FORMAT (TYPE_MODE (TREE_TYPE (arg))); - - if (!real_isfinite (rvp)) - { - /* The format for Infinity and NaN is "[-]inf"/"[-]infinity" - and "[-]nan" with the choice being implementation-defined - but not locale dependent. */ - bool sign = dir.get_flag ('+') || real_isneg (rvp); - res.range.min = 3 + sign; - - res.range.likely = res.range.min; - res.range.max = res.range.min; - /* The unlikely maximum is "[-/+]infinity" or "[-/+][qs]nan". - For NaN, the C/POSIX standards specify two formats: - "[-/+]nan" - and - "[-/+]nan(n-char-sequence)" - No known printf implementation outputs the latter format but AIX - outputs QNaN and SNaN for quiet and signalling NaN, respectively, - so the unlikely maximum reflects that. */ - res.range.unlikely = sign + (real_isinf (rvp) ? 8 : 4); - - /* The range for infinity and NaN is known unless either width - or precision is unknown. Width has the same effect regardless - of whether the argument is finite. Precision is either ignored - (e.g., Glibc) or can have an effect on the short vs long format - such as inf/infinity (e.g., Solaris). */ - res.knownrange = dir.known_width_and_precision (); - - /* Adjust the range for width but ignore precision. */ - res.adjust_for_width_or_precision (dir.width); - - return res; - } - - char fmtstr [40]; - char *pfmt = fmtstr; - - /* Append flags. */ - for (const char *pf = "-+ #0"; *pf; ++pf) - if (dir.get_flag (*pf)) - *pfmt++ = *pf; - - *pfmt = '\0'; - - { - /* Set up an array to easily iterate over. */ - unsigned HOST_WIDE_INT* const minmax[] = { - &res.range.min, &res.range.max - }; - - for (int i = 0; i != sizeof minmax / sizeof *minmax; ++i) - { - /* Convert the GCC real value representation with the precision - of the real type to the mpfr_t format rounding down in the - first iteration that computes the minimum and up in the second - that computes the maximum. This order is arbitrary because - rounding in either direction can result in longer output. */ - mpfr_t mpfrval; - mpfr_init2 (mpfrval, rfmt->p); - mpfr_from_real (mpfrval, rvp, i ? MPFR_RNDU : MPFR_RNDD); - - /* Use the MPFR rounding specifier to round down in the first - iteration and then up. In most but not all cases this will - result in the same number of bytes. */ - char rndspec = "DU"[i]; - - /* Format it and store the result in the corresponding member - of the result struct. */ - *minmax[i] = get_mpfr_format_length (mpfrval, fmtstr, prec[i], - dir.specifier, rndspec); - mpfr_clear (mpfrval); - } - } - - /* Make sure the minimum is less than the maximum (MPFR rounding - in the call to mpfr_snprintf can result in the reverse. */ - if (res.range.max < res.range.min) - { - unsigned HOST_WIDE_INT tmp = res.range.min; - res.range.min = res.range.max; - res.range.max = tmp; - } - - /* The range is known unless either width or precision is unknown. */ - res.knownrange = dir.known_width_and_precision (); - - /* For the same floating point constant, unless width or precision - is unknown, use the longer output as the likely maximum since - with round to nearest either is equally likely. Otherwise, when - precision is unknown, use the greater of the minimum and 3 as - the likely output (for "0.0" since zero precision is unlikely). */ - if (res.knownrange) - res.range.likely = res.range.max; - else if (res.range.min < 3 - && dir.prec[0] < 0 - && (unsigned HOST_WIDE_INT)dir.prec[1] == target_int_max ()) - res.range.likely = 3; - else - res.range.likely = res.range.min; - - res.range.unlikely = res.range.max; - - if (res.range.max > 2 && (prec[0] != 0 || prec[1] != 0)) - { - /* Unless the precision is zero output longer than 2 bytes may - include the decimal point which must be a single character - up to MB_LEN_MAX in length. This is overly conservative - since in some conversions some constants result in no decimal - point (e.g., in %g). */ - res.range.unlikely += target_mb_len_max () - 1; - } - - res.adjust_for_width_or_precision (dir.width); - return res; -} - -/* Return a FMTRESULT struct set to the lengths of the shortest and longest - strings referenced by the expression STR, or (-1, -1) when not known. - Used by the format_string function below. */ - -static fmtresult -get_string_length (tree str, gimple *stmt, unsigned HOST_WIDE_INT max_size, - unsigned eltsize, range_query *query) -{ - if (!str) - return fmtresult (); - - /* Try to determine the dynamic string length first. - Set MAXBOUND to an arbitrary non-null non-integer node as a request - to have it set to the length of the longest string in a PHI. */ - c_strlen_data lendata = { }; - lendata.maxbound = str; - if (eltsize == 1) - get_range_strlen_dynamic (str, stmt, &lendata, query); - else - { - /* Determine the length of the shortest and longest string referenced - by STR. Strings of unknown lengths are bounded by the sizes of - arrays that subexpressions of STR may refer to. Pointers that - aren't known to point any such arrays result in LENDATA.MAXLEN - set to SIZE_MAX. */ - get_range_strlen (str, &lendata, eltsize); - } - - /* If LENDATA.MAXBOUND is not equal to .MINLEN it corresponds to the bound - of the largest array STR refers to, if known, or it's set to SIZE_MAX - otherwise. */ - - /* Return the default result when nothing is known about the string. */ - if ((lendata.maxbound && !tree_fits_uhwi_p (lendata.maxbound)) - || !tree_fits_uhwi_p (lendata.maxlen)) - { - fmtresult res; - res.nonstr = lendata.decl; - return res; - } - - unsigned HOST_WIDE_INT lenmax = tree_to_uhwi (max_object_size ()) - 2; - if (integer_zerop (lendata.minlen) - && (!lendata.maxbound || lenmax <= tree_to_uhwi (lendata.maxbound)) - && lenmax <= tree_to_uhwi (lendata.maxlen)) - { - if (max_size > 0 && max_size < HOST_WIDE_INT_MAX) - { - /* Adjust the conservative unknown/unbounded result if MAX_SIZE - is valid. Set UNLIKELY to maximum in case MAX_SIZE refers - to a subobject. - TODO: This is overly conservative. Set UNLIKELY to the size - of the outermost enclosing declared object. */ - fmtresult res (0, max_size - 1); - res.nonstr = lendata.decl; - res.range.likely = res.range.max; - res.range.unlikely = HOST_WIDE_INT_MAX; - return res; - } - - fmtresult res; - res.nonstr = lendata.decl; - return res; - } - - HOST_WIDE_INT min - = (tree_fits_uhwi_p (lendata.minlen) - ? tree_to_uhwi (lendata.minlen) - : 0); - - HOST_WIDE_INT max - = (lendata.maxbound && tree_fits_uhwi_p (lendata.maxbound) - ? tree_to_uhwi (lendata.maxbound) - : HOST_WIDE_INT_M1U); - - const bool unbounded = integer_all_onesp (lendata.maxlen); - - /* Set the max/likely counters to unbounded when a minimum is known - but the maximum length isn't bounded. This implies that STR is - a conditional expression involving a string of known length and - an expression of unknown/unbounded length. */ - if (min - && (unsigned HOST_WIDE_INT)min < HOST_WIDE_INT_M1U - && unbounded) - max = HOST_WIDE_INT_M1U; - - /* get_range_strlen() returns the target value of SIZE_MAX for - strings of unknown length. Bump it up to HOST_WIDE_INT_M1U - which may be bigger. */ - if ((unsigned HOST_WIDE_INT)min == target_size_max ()) - min = HOST_WIDE_INT_M1U; - if ((unsigned HOST_WIDE_INT)max == target_size_max ()) - max = HOST_WIDE_INT_M1U; - - fmtresult res (min, max); - res.nonstr = lendata.decl; - - /* Set RES.KNOWNRANGE to true if and only if all strings referenced - by STR are known to be bounded (though not necessarily by their - actual length but perhaps by their maximum possible length). */ - if (res.range.max < target_int_max ()) - { - res.knownrange = true; - /* When the length of the longest string is known and not - excessive use it as the likely length of the string(s). */ - res.range.likely = res.range.max; - } - else - { - /* When the upper bound is unknown (it can be zero or excessive) - set the likely length to the greater of 1. If MAXBOUND is - known, also reset the length of the lower bound to zero. */ - res.range.likely = res.range.min ? res.range.min : warn_level > 1; - if (lendata.maxbound && !integer_all_onesp (lendata.maxbound)) - res.range.min = 0; - } - - res.range.unlikely = unbounded ? HOST_WIDE_INT_MAX : res.range.max; - - return res; -} - -/* Return the minimum and maximum number of characters formatted - by the '%c' format directives and its wide character form for - the argument ARG. ARG can be null (for functions such as - vsprinf). */ - -static fmtresult -format_character (const directive &dir, tree arg, range_query *query) -{ - fmtresult res; - - res.knownrange = true; - - if (dir.specifier == 'C' - || dir.modifier == FMT_LEN_l) - { - /* A wide character can result in as few as zero bytes. */ - res.range.min = 0; - - HOST_WIDE_INT min, max; - if (get_int_range (arg, dir.info->callstmt, &min, &max, false, 0, query)) - { - if (min == 0 && max == 0) - { - /* The NUL wide character results in no bytes. */ - res.range.max = 0; - res.range.likely = 0; - res.range.unlikely = 0; - } - else if (min >= 0 && min < 128) - { - /* Be conservative if the target execution character set - is not a 1-to-1 mapping to the source character set or - if the source set is not ASCII. */ - bool one_2_one_ascii - = (target_to_host_charmap[0] == 1 && target_to_host ('a') == 97); - - /* A wide character in the ASCII range most likely results - in a single byte, and only unlikely in up to MB_LEN_MAX. */ - res.range.max = one_2_one_ascii ? 1 : target_mb_len_max ();; - res.range.likely = 1; - res.range.unlikely = target_mb_len_max (); - res.mayfail = !one_2_one_ascii; - } - else - { - /* A wide character outside the ASCII range likely results - in up to two bytes, and only unlikely in up to MB_LEN_MAX. */ - res.range.max = target_mb_len_max (); - res.range.likely = 2; - res.range.unlikely = res.range.max; - /* Converting such a character may fail. */ - res.mayfail = true; - } - } - else - { - /* An unknown wide character is treated the same as a wide - character outside the ASCII range. */ - res.range.max = target_mb_len_max (); - res.range.likely = 2; - res.range.unlikely = res.range.max; - res.mayfail = true; - } - } - else - { - /* A plain '%c' directive. Its output is exactly 1. */ - res.range.min = res.range.max = 1; - res.range.likely = res.range.unlikely = 1; - res.knownrange = true; - } - - /* Bump up the byte counters if WIDTH is greater. */ - return res.adjust_for_width_or_precision (dir.width); -} - -/* If TYPE is an array or struct or union, increment *FLDOFF by the starting - offset of the member that *OFF point into and set *FLDSIZE to its size - in bytes and decrement *OFF by the same. Otherwise do nothing. */ - -static void -set_aggregate_size_and_offset (tree type, HOST_WIDE_INT *fldoff, - HOST_WIDE_INT *fldsize, HOST_WIDE_INT *off) -{ - /* The byte offset of the most basic struct member the byte - offset *OFF corresponds to, or for a (multidimensional) - array member, the byte offset of the array element. */ - if (TREE_CODE (type) == ARRAY_TYPE - && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE) - { - HOST_WIDE_INT index = 0, arrsize = 0; - if (array_elt_at_offset (type, *off, &index, &arrsize)) - { - *fldoff += index; - *off -= index; - *fldsize = arrsize; - } - } - else if (RECORD_OR_UNION_TYPE_P (type)) - { - HOST_WIDE_INT index = 0; - tree sub = field_at_offset (type, NULL_TREE, *off, &index); - if (sub) - { - tree subsize = DECL_SIZE_UNIT (sub); - if (*fldsize < HOST_WIDE_INT_MAX - && subsize - && tree_fits_uhwi_p (subsize)) - *fldsize = tree_to_uhwi (subsize); - else - *fldsize = HOST_WIDE_INT_MAX; - *fldoff += index; - *off -= index; - } - } -} - -/* For an expression X of pointer type, recursively try to find the same - origin (object or pointer) as Y it references and return such a Y. - When X refers to an array element or struct member, set *FLDOFF to - the offset of the element or member from the beginning of the "most - derived" object and *FLDSIZE to its size. When nonnull, set *OFF to - the overall offset from the beginning of the object so that - *FLDOFF <= *OFF. */ - -static tree -get_origin_and_offset_r (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *fldsize, - HOST_WIDE_INT *off) -{ - if (!x) - return NULL_TREE; - - HOST_WIDE_INT sizebuf = -1; - if (!fldsize) - fldsize = &sizebuf; - - if (DECL_P (x)) - { - /* Set the size if it hasn't been set yet. */ - if (tree size = DECL_SIZE_UNIT (x)) - if (*fldsize < 0 && tree_fits_shwi_p (size)) - *fldsize = tree_to_shwi (size); - return x; - } - - switch (TREE_CODE (x)) - { - case ADDR_EXPR: - x = TREE_OPERAND (x, 0); - return get_origin_and_offset_r (x, fldoff, fldsize, off); - - case ARRAY_REF: - { - tree offset = TREE_OPERAND (x, 1); - HOST_WIDE_INT idx = (tree_fits_uhwi_p (offset) - ? tree_to_uhwi (offset) : HOST_WIDE_INT_MAX); - - tree eltype = TREE_TYPE (x); - if (TREE_CODE (eltype) == INTEGER_TYPE) - { - if (off) - *off = idx; - } - else if (idx < HOST_WIDE_INT_MAX) - *fldoff += idx * int_size_in_bytes (eltype); - else - *fldoff = idx; - - x = TREE_OPERAND (x, 0); - return get_origin_and_offset_r (x, fldoff, fldsize, nullptr); - } - - case MEM_REF: - if (off) - { - tree offset = TREE_OPERAND (x, 1); - *off = (tree_fits_uhwi_p (offset) - ? tree_to_uhwi (offset) : HOST_WIDE_INT_MAX); - } - - x = TREE_OPERAND (x, 0); - - if (off) - { - tree xtype - = (TREE_CODE (x) == ADDR_EXPR - ? TREE_TYPE (TREE_OPERAND (x, 0)) : TREE_TYPE (TREE_TYPE (x))); - - set_aggregate_size_and_offset (xtype, fldoff, fldsize, off); - } - - return get_origin_and_offset_r (x, fldoff, fldsize, nullptr); - - case COMPONENT_REF: - { - tree fld = TREE_OPERAND (x, 1); - *fldoff += int_byte_position (fld); - - get_origin_and_offset_r (fld, fldoff, fldsize, off); - x = TREE_OPERAND (x, 0); - return get_origin_and_offset_r (x, fldoff, nullptr, off); - } - - case SSA_NAME: - { - gimple *def = SSA_NAME_DEF_STMT (x); - if (is_gimple_assign (def)) - { - tree_code code = gimple_assign_rhs_code (def); - if (code == ADDR_EXPR) - { - x = gimple_assign_rhs1 (def); - return get_origin_and_offset_r (x, fldoff, fldsize, off); - } - - if (code == POINTER_PLUS_EXPR) - { - tree offset = gimple_assign_rhs2 (def); - if (off && tree_fits_uhwi_p (offset)) - *off = tree_to_uhwi (offset); - - x = gimple_assign_rhs1 (def); - x = get_origin_and_offset_r (x, fldoff, fldsize, off); - if (off && !tree_fits_uhwi_p (offset)) - *off = HOST_WIDE_INT_MAX; - if (off) - { - tree xtype = TREE_TYPE (x); - set_aggregate_size_and_offset (xtype, fldoff, fldsize, off); - } - return x; - } - else if (code == VAR_DECL) - { - x = gimple_assign_rhs1 (def); - return get_origin_and_offset_r (x, fldoff, fldsize, off); - } - } - else if (gimple_nop_p (def) && SSA_NAME_VAR (x)) - x = SSA_NAME_VAR (x); - - tree xtype = TREE_TYPE (x); - if (POINTER_TYPE_P (xtype)) - xtype = TREE_TYPE (xtype); - - if (off) - set_aggregate_size_and_offset (xtype, fldoff, fldsize, off); - } - - default: - break; - } - - return x; -} - -/* Nonrecursive version of the above. */ - -static tree -get_origin_and_offset (tree x, HOST_WIDE_INT *fldoff, HOST_WIDE_INT *off, - HOST_WIDE_INT *fldsize = nullptr) -{ - HOST_WIDE_INT sizebuf; - if (!fldsize) - fldsize = &sizebuf; - - *fldsize = -1; - - *fldoff = *off = *fldsize = 0; - tree orig = get_origin_and_offset_r (x, fldoff, fldsize, off); - if (!orig) - return NULL_TREE; - - if (!*fldoff && *off == *fldsize) - { - *fldoff = *off; - *off = 0; - } - - return orig; -} - -/* If ARG refers to the same (sub)object or array element as described - by DST and DST_FLD, return the byte offset into the struct member or - array element referenced by ARG and set *ARG_SIZE to the size of - the (sub)object. Otherwise return HOST_WIDE_INT_MIN to indicate - that ARG and DST do not refer to the same object. */ - -static HOST_WIDE_INT -alias_offset (tree arg, HOST_WIDE_INT *arg_size, - tree dst, HOST_WIDE_INT dst_fld) -{ - /* See if the argument refers to the same base object as the destination - of the formatted function call, and if so, try to determine if they - can alias. */ - if (!arg || !dst || !ptr_derefs_may_alias_p (arg, dst)) - return HOST_WIDE_INT_MIN; - - /* The two arguments may refer to the same object. If they both refer - to a struct member, see if the members are one and the same. */ - HOST_WIDE_INT arg_off = 0, arg_fld = 0; - - tree arg_orig = get_origin_and_offset (arg, &arg_fld, &arg_off, arg_size); - - if (arg_orig == dst && arg_fld == dst_fld) - return arg_off; - - return HOST_WIDE_INT_MIN; -} - -/* Return the minimum and maximum number of characters formatted - by the '%s' format directive and its wide character form for - the argument ARG. ARG can be null (for functions such as - vsprinf). */ - -static fmtresult -format_string (const directive &dir, tree arg, range_query *query) -{ - fmtresult res; - - /* The size of the (sub)object ARG refers to. Used to adjust - the conservative get_string_length() result. */ - HOST_WIDE_INT arg_size = 0; - - if (warn_restrict) - { - /* See if ARG might alias the destination of the call with - DST_ORIGIN and DST_FIELD. If so, store the starting offset - so that the overlap can be determined for certain later, - when the amount of output of the call (including subsequent - directives) has been computed. Otherwise, store HWI_MIN. */ - res.dst_offset = alias_offset (arg, &arg_size, dir.info->dst_origin, - dir.info->dst_field); - if (res.dst_offset >= 0 && res.dst_offset <= arg_size) - arg_size -= res.dst_offset; - else - arg_size = 0; - } - - /* Compute the range the argument's length can be in. */ - int count_by = 1; - if (dir.specifier == 'S' || dir.modifier == FMT_LEN_l) - { - /* Get a node for a C type that will be the same size - as a wchar_t on the target. */ - tree node = get_typenode_from_name (MODIFIED_WCHAR_TYPE); - - /* Now that we have a suitable node, get the number of - bytes it occupies. */ - count_by = int_size_in_bytes (node); - gcc_checking_assert (count_by == 2 || count_by == 4); - } - - fmtresult slen = - get_string_length (arg, dir.info->callstmt, arg_size, count_by, query); - if (slen.range.min == slen.range.max - && slen.range.min < HOST_WIDE_INT_MAX) - { - /* The argument is either a string constant or it refers - to one of a number of strings of the same length. */ - - /* A '%s' directive with a string argument with constant length. */ - res.range = slen.range; - - if (dir.specifier == 'S' - || dir.modifier == FMT_LEN_l) - { - /* In the worst case the length of output of a wide string S - is bounded by MB_LEN_MAX * wcslen (S). */ - res.range.max *= target_mb_len_max (); - res.range.unlikely = res.range.max; - /* It's likely that the total length is not more that - 2 * wcslen (S).*/ - res.range.likely = res.range.min * 2; - - if (dir.prec[1] >= 0 - && (unsigned HOST_WIDE_INT)dir.prec[1] < res.range.max) - { - res.range.max = dir.prec[1]; - res.range.likely = dir.prec[1]; - res.range.unlikely = dir.prec[1]; - } - - if (dir.prec[0] < 0 && dir.prec[1] > -1) - res.range.min = 0; - else if (dir.prec[0] >= 0) - res.range.likely = dir.prec[0]; - - /* Even a non-empty wide character string need not convert into - any bytes. */ - res.range.min = 0; - - /* A non-empty wide character conversion may fail. */ - if (slen.range.max > 0) - res.mayfail = true; - } - else - { - res.knownrange = true; - - if (dir.prec[0] < 0 && dir.prec[1] > -1) - res.range.min = 0; - else if ((unsigned HOST_WIDE_INT)dir.prec[0] < res.range.min) - res.range.min = dir.prec[0]; - - if ((unsigned HOST_WIDE_INT)dir.prec[1] < res.range.max) - { - res.range.max = dir.prec[1]; - res.range.likely = dir.prec[1]; - res.range.unlikely = dir.prec[1]; - } - } - } - else if (arg && integer_zerop (arg)) - { - /* Handle null pointer argument. */ - - fmtresult res (0); - res.nullp = true; - return res; - } - else - { - /* For a '%s' and '%ls' directive with a non-constant string (either - one of a number of strings of known length or an unknown string) - the minimum number of characters is lesser of PRECISION[0] and - the length of the shortest known string or zero, and the maximum - is the lesser of the length of the longest known string or - PTRDIFF_MAX and PRECISION[1]. The likely length is either - the minimum at level 1 and the greater of the minimum and 1 - at level 2. This result is adjust upward for width (if it's - specified). */ - - if (dir.specifier == 'S' - || dir.modifier == FMT_LEN_l) - { - /* A wide character converts to as few as zero bytes. */ - slen.range.min = 0; - if (slen.range.max < target_int_max ()) - slen.range.max *= target_mb_len_max (); - - if (slen.range.likely < target_int_max ()) - slen.range.likely *= 2; - - if (slen.range.likely < target_int_max ()) - slen.range.unlikely *= target_mb_len_max (); - - /* A non-empty wide character conversion may fail. */ - if (slen.range.max > 0) - res.mayfail = true; - } - - res.range = slen.range; - - if (dir.prec[0] >= 0) - { - /* Adjust the minimum to zero if the string length is unknown, - or at most the lower bound of the precision otherwise. */ - if (slen.range.min >= target_int_max ()) - res.range.min = 0; - else if ((unsigned HOST_WIDE_INT)dir.prec[0] < slen.range.min) - res.range.min = dir.prec[0]; - - /* Make both maxima no greater than the upper bound of precision. */ - if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.max - || slen.range.max >= target_int_max ()) - { - res.range.max = dir.prec[1]; - res.range.unlikely = dir.prec[1]; - } - - /* If precision is constant, set the likely counter to the lesser - of it and the maximum string length. Otherwise, if the lower - bound of precision is greater than zero, set the likely counter - to the minimum. Otherwise set it to zero or one based on - the warning level. */ - if (dir.prec[0] == dir.prec[1]) - res.range.likely - = ((unsigned HOST_WIDE_INT)dir.prec[0] < slen.range.max - ? dir.prec[0] : slen.range.max); - else if (dir.prec[0] > 0) - res.range.likely = res.range.min; - else - res.range.likely = warn_level > 1; - } - else if (dir.prec[1] >= 0) - { - res.range.min = 0; - if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.max) - res.range.max = dir.prec[1]; - res.range.likely = dir.prec[1] ? warn_level > 1 : 0; - if ((unsigned HOST_WIDE_INT)dir.prec[1] < slen.range.unlikely) - res.range.unlikely = dir.prec[1]; - } - else if (slen.range.min >= target_int_max ()) - { - res.range.min = 0; - res.range.max = HOST_WIDE_INT_MAX; - /* At level 1 strings of unknown length are assumed to be - empty, while at level 1 they are assumed to be one byte - long. */ - res.range.likely = warn_level > 1; - res.range.unlikely = HOST_WIDE_INT_MAX; - } - else - { - /* A string of unknown length unconstrained by precision is - assumed to be empty at level 1 and just one character long - at higher levels. */ - if (res.range.likely >= target_int_max ()) - res.range.likely = warn_level > 1; - } - } - - /* If the argument isn't a nul-terminated string and the number - of bytes on output isn't bounded by precision, set NONSTR. */ - if (slen.nonstr && slen.range.min < (unsigned HOST_WIDE_INT)dir.prec[0]) - res.nonstr = slen.nonstr; - - /* Bump up the byte counters if WIDTH is greater. */ - return res.adjust_for_width_or_precision (dir.width); -} - -/* Format plain string (part of the format string itself). */ - -static fmtresult -format_plain (const directive &dir, tree, range_query *) -{ - fmtresult res (dir.len); - return res; -} - -/* Return true if the RESULT of a directive in a call describe by INFO - should be diagnosed given the AVAILable space in the destination. */ - -static bool -should_warn_p (const call_info &info, - const result_range &avail, const result_range &result) -{ - if (result.max <= avail.min) - { - /* The least amount of space remaining in the destination is big - enough for the longest output. */ - return false; - } - - if (info.bounded) - { - if (warn_format_trunc == 1 && result.min <= avail.max - && info.retval_used ()) - { - /* The likely amount of space remaining in the destination is big - enough for the least output and the return value is used. */ - return false; - } - - if (warn_format_trunc == 1 && result.likely <= avail.likely - && !info.retval_used ()) - { - /* The likely amount of space remaining in the destination is big - enough for the likely output and the return value is unused. */ - return false; - } - - if (warn_format_trunc == 2 - && result.likely <= avail.min - && (result.max <= avail.min - || result.max > HOST_WIDE_INT_MAX)) - { - /* The minimum amount of space remaining in the destination is big - enough for the longest output. */ - return false; - } - } - else - { - if (warn_level == 1 && result.likely <= avail.likely) - { - /* The likely amount of space remaining in the destination is big - enough for the likely output. */ - return false; - } - - if (warn_level == 2 - && result.likely <= avail.min - && (result.max <= avail.min - || result.max > HOST_WIDE_INT_MAX)) - { - /* The minimum amount of space remaining in the destination is big - enough for the longest output. */ - return false; - } - } - - return true; -} - -/* At format string location describe by DIRLOC in a call described - by INFO, issue a warning for a directive DIR whose output may be - in excess of the available space AVAIL_RANGE in the destination - given the formatting result FMTRES. This function does nothing - except decide whether to issue a warning for a possible write - past the end or truncation and, if so, format the warning. - Return true if a warning has been issued. */ - -static bool -maybe_warn (substring_loc &dirloc, location_t argloc, - const call_info &info, - const result_range &avail_range, const result_range &res, - const directive &dir) -{ - if (!should_warn_p (info, avail_range, res)) - return false; - - /* A warning will definitely be issued below. */ - - /* The maximum byte count to reference in the warning. Larger counts - imply that the upper bound is unknown (and could be anywhere between - RES.MIN + 1 and SIZE_MAX / 2) are printed as "N or more bytes" rather - than "between N and X" where X is some huge number. */ - unsigned HOST_WIDE_INT maxbytes = target_dir_max (); - - /* True when there is enough room in the destination for the least - amount of a directive's output but not enough for its likely or - maximum output. */ - bool maybe = (res.min <= avail_range.max - && (avail_range.min < res.likely - || (res.max < HOST_WIDE_INT_MAX - && avail_range.min < res.max))); - - /* Buffer for the directive in the host character set (used when - the source character set is different). */ - char hostdir[32]; - - if (avail_range.min == avail_range.max) - { - /* The size of the destination region is exact. */ - unsigned HOST_WIDE_INT navail = avail_range.max; - - if (target_to_host (*dir.beg) != '%') - { - /* For plain character directives (i.e., the format string itself) - but not others, point the caret at the first character that's - past the end of the destination. */ - if (navail < dir.len) - dirloc.set_caret_index (dirloc.get_caret_idx () + navail); - } - - if (*dir.beg == '\0') - { - /* This is the terminating nul. */ - gcc_assert (res.min == 1 && res.min == res.max); - - return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%qE output may be truncated before the " - "last format character") - : G_("%qE output truncated before the last " - "format character")) - : (maybe - ? G_("%qE may write a terminating nul past the " - "end of the destination") - : G_("%qE writing a terminating nul past the " - "end of the destination")), - info.func); - } - - if (res.min == res.max) - { - const char *d = target_to_host (hostdir, sizeof hostdir, dir.beg); - if (!info.bounded) - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive writing %wu byte into a " - "region of size %wu", - "%<%.*s%> directive writing %wu bytes into a " - "region of size %wu", - (int) dir.len, d, res.min, navail); - else if (maybe) - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive output may be truncated " - "writing %wu byte into a region of size %wu", - "%<%.*s%> directive output may be truncated " - "writing %wu bytes into a region of size %wu", - (int) dir.len, d, res.min, navail); - else - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive output truncated writing " - "%wu byte into a region of size %wu", - "%<%.*s%> directive output truncated writing " - "%wu bytes into a region of size %wu", - (int) dir.len, d, res.min, navail); - } - if (res.min == 0 && res.max < maxbytes) - return fmtwarn (dirloc, argloc, NULL, - info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing up to %wu bytes into a region of " - "size %wu") - : G_("%<%.*s%> directive output truncated writing " - "up to %wu bytes into a region of size %wu")) - : G_("%<%.*s%> directive writing up to %wu bytes " - "into a region of size %wu"), (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.max, navail); - - if (res.min == 0 && maxbytes <= res.max) - /* This is a special case to avoid issuing the potentially - confusing warning: - writing 0 or more bytes into a region of size 0. */ - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing likely %wu or more bytes into a " - "region of size %wu") - : G_("%<%.*s%> directive output truncated writing " - "likely %wu or more bytes into a region of " - "size %wu")) - : G_("%<%.*s%> directive writing likely %wu or more " - "bytes into a region of size %wu"), (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.likely, navail); - - if (res.max < maxbytes) - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing between %wu and %wu bytes into a " - "region of size %wu") - : G_("%<%.*s%> directive output truncated " - "writing between %wu and %wu bytes into a " - "region of size %wu")) - : G_("%<%.*s%> directive writing between %wu and " - "%wu bytes into a region of size %wu"), - (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.min, res.max, navail); - - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing %wu or more bytes into a region of " - "size %wu") - : G_("%<%.*s%> directive output truncated writing " - "%wu or more bytes into a region of size %wu")) - : G_("%<%.*s%> directive writing %wu or more bytes " - "into a region of size %wu"), (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.min, navail); - } - - /* The size of the destination region is a range. */ - - if (target_to_host (*dir.beg) != '%') - { - unsigned HOST_WIDE_INT navail = avail_range.max; - - /* For plain character directives (i.e., the format string itself) - but not others, point the caret at the first character that's - past the end of the destination. */ - if (navail < dir.len) - dirloc.set_caret_index (dirloc.get_caret_idx () + navail); - } - - if (*dir.beg == '\0') - { - gcc_assert (res.min == 1 && res.min == res.max); - - return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%qE output may be truncated before the last " - "format character") - : G_("%qE output truncated before the last format " - "character")) - : (maybe - ? G_("%qE may write a terminating nul past the end " - "of the destination") - : G_("%qE writing a terminating nul past the end " - "of the destination")), info.func); - } - - if (res.min == res.max) - { - const char *d = target_to_host (hostdir, sizeof hostdir, dir.beg); - if (!info.bounded) - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive writing %wu byte into a region " - "of size between %wu and %wu", - "%<%.*s%> directive writing %wu bytes into a region " - "of size between %wu and %wu", (int) dir.len, d, - res.min, avail_range.min, avail_range.max); - else if (maybe) - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive output may be truncated writing " - "%wu byte into a region of size between %wu and %wu", - "%<%.*s%> directive output may be truncated writing " - "%wu bytes into a region of size between %wu and " - "%wu", (int) dir.len, d, res.min, avail_range.min, - avail_range.max); - else - return fmtwarn_n (dirloc, argloc, NULL, info.warnopt (), res.min, - "%<%.*s%> directive output truncated writing %wu " - "byte into a region of size between %wu and %wu", - "%<%.*s%> directive output truncated writing %wu " - "bytes into a region of size between %wu and %wu", - (int) dir.len, d, res.min, avail_range.min, - avail_range.max); - } - - if (res.min == 0 && res.max < maxbytes) - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing up to %wu bytes into a region of size " - "between %wu and %wu") - : G_("%<%.*s%> directive output truncated writing " - "up to %wu bytes into a region of size between " - "%wu and %wu")) - : G_("%<%.*s%> directive writing up to %wu bytes " - "into a region of size between %wu and %wu"), - (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.max, avail_range.min, avail_range.max); - - if (res.min == 0 && maxbytes <= res.max) - /* This is a special case to avoid issuing the potentially confusing - warning: - writing 0 or more bytes into a region of size between 0 and N. */ - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing likely %wu or more bytes into a region " - "of size between %wu and %wu") - : G_("%<%.*s%> directive output truncated writing " - "likely %wu or more bytes into a region of size " - "between %wu and %wu")) - : G_("%<%.*s%> directive writing likely %wu or more bytes " - "into a region of size between %wu and %wu"), - (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.likely, avail_range.min, avail_range.max); - - if (res.max < maxbytes) - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated " - "writing between %wu and %wu bytes into a region " - "of size between %wu and %wu") - : G_("%<%.*s%> directive output truncated writing " - "between %wu and %wu bytes into a region of size " - "between %wu and %wu")) - : G_("%<%.*s%> directive writing between %wu and " - "%wu bytes into a region of size between %wu and " - "%wu"), (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.min, res.max, avail_range.min, avail_range.max); - - return fmtwarn (dirloc, argloc, NULL, info.warnopt (), - info.bounded - ? (maybe - ? G_("%<%.*s%> directive output may be truncated writing " - "%wu or more bytes into a region of size between " - "%wu and %wu") - : G_("%<%.*s%> directive output truncated writing " - "%wu or more bytes into a region of size between " - "%wu and %wu")) - : G_("%<%.*s%> directive writing %wu or more bytes " - "into a region of size between %wu and %wu"), - (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg), - res.min, avail_range.min, avail_range.max); -} - -/* Given the formatting result described by RES and NAVAIL, the number - of available bytes in the destination, return the range of bytes - remaining in the destination. */ - -static inline result_range -bytes_remaining (unsigned HOST_WIDE_INT navail, const format_result &res) -{ - result_range range; - - if (HOST_WIDE_INT_MAX <= navail) - { - range.min = range.max = range.likely = range.unlikely = navail; - return range; - } - - /* The lower bound of the available range is the available size - minus the maximum output size, and the upper bound is the size - minus the minimum. */ - range.max = res.range.min < navail ? navail - res.range.min : 0; - - range.likely = res.range.likely < navail ? navail - res.range.likely : 0; - - if (res.range.max < HOST_WIDE_INT_MAX) - range.min = res.range.max < navail ? navail - res.range.max : 0; - else - range.min = range.likely; - - range.unlikely = (res.range.unlikely < navail - ? navail - res.range.unlikely : 0); - - return range; -} - -/* Compute the length of the output resulting from the directive DIR - in a call described by INFO and update the overall result of the call - in *RES. Return true if the directive has been handled. */ - -static bool -format_directive (const call_info &info, - format_result *res, const directive &dir, - range_query *query) -{ - /* Offset of the beginning of the directive from the beginning - of the format string. */ - size_t offset = dir.beg - info.fmtstr; - size_t start = offset; - size_t length = offset + dir.len - !!dir.len; - - /* Create a location for the whole directive from the % to the format - specifier. */ - substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format), - offset, start, length); - - /* Also get the location of the argument if possible. - This doesn't work for integer literals or function calls. */ - location_t argloc = UNKNOWN_LOCATION; - if (dir.arg) - argloc = EXPR_LOCATION (dir.arg); - - /* Bail when there is no function to compute the output length, - or when minimum length checking has been disabled. */ - if (!dir.fmtfunc || res->range.min >= HOST_WIDE_INT_MAX) - return false; - - /* Compute the range of lengths of the formatted output. */ - fmtresult fmtres = dir.fmtfunc (dir, dir.arg, query); - - /* Record whether the output of all directives is known to be - bounded by some maximum, implying that their arguments are - either known exactly or determined to be in a known range - or, for strings, limited by the upper bounds of the arrays - they refer to. */ - res->knownrange &= fmtres.knownrange; - - if (!fmtres.knownrange) - { - /* Only when the range is known, check it against the host value - of INT_MAX + (the number of bytes of the "%.*Lf" directive with - INT_MAX precision, which is the longest possible output of any - single directive). That's the largest valid byte count (though - not valid call to a printf-like function because it can never - return such a count). Otherwise, the range doesn't correspond - to known values of the argument. */ - if (fmtres.range.max > target_dir_max ()) - { - /* Normalize the MAX counter to avoid having to deal with it - later. The counter can be less than HOST_WIDE_INT_M1U - when compiling for an ILP32 target on an LP64 host. */ - fmtres.range.max = HOST_WIDE_INT_M1U; - /* Disable exact and maximum length checking after a failure - to determine the maximum number of characters (for example - for wide characters or wide character strings) but continue - tracking the minimum number of characters. */ - res->range.max = HOST_WIDE_INT_M1U; - } - - if (fmtres.range.min > target_dir_max ()) - { - /* Disable exact length checking after a failure to determine - even the minimum number of characters (it shouldn't happen - except in an error) but keep tracking the minimum and maximum - number of characters. */ - return true; - } - } - - /* Buffer for the directive in the host character set (used when - the source character set is different). */ - char hostdir[32]; - - int dirlen = dir.len; - - if (fmtres.nullp) - { - fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive argument is null", - dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg)); - - /* Don't bother processing the rest of the format string. */ - res->warned = true; - res->range.min = HOST_WIDE_INT_M1U; - res->range.max = HOST_WIDE_INT_M1U; - return false; - } - - /* Compute the number of available bytes in the destination. There - must always be at least one byte of space for the terminating - NUL that's appended after the format string has been processed. */ - result_range avail_range = bytes_remaining (info.objsize, *res); - - /* If the argument aliases a part of the destination of the formatted - call at offset FMTRES.DST_OFFSET append the directive and its result - to the set of aliases for later processing. */ - if (fmtres.dst_offset != HOST_WIDE_INT_MIN) - res->append_alias (dir, fmtres.dst_offset, fmtres.range); - - bool warned = res->warned; - - if (!warned) - warned = maybe_warn (dirloc, argloc, info, avail_range, - fmtres.range, dir); - - /* Bump up the total maximum if it isn't too big. */ - if (res->range.max < HOST_WIDE_INT_MAX - && fmtres.range.max < HOST_WIDE_INT_MAX) - res->range.max += fmtres.range.max; - - /* Raise the total unlikely maximum by the larger of the maximum - and the unlikely maximum. */ - unsigned HOST_WIDE_INT save = res->range.unlikely; - if (fmtres.range.max < fmtres.range.unlikely) - res->range.unlikely += fmtres.range.unlikely; - else - res->range.unlikely += fmtres.range.max; - - if (res->range.unlikely < save) - res->range.unlikely = HOST_WIDE_INT_M1U; - - res->range.min += fmtres.range.min; - res->range.likely += fmtres.range.likely; - - /* Has the minimum directive output length exceeded the maximum - of 4095 bytes required to be supported? */ - bool minunder4k = fmtres.range.min < 4096; - bool maxunder4k = fmtres.range.max < 4096; - /* Clear POSUNDER4K in the overall result if the maximum has exceeded - the 4k (this is necessary to avoid the return value optimization - that may not be safe in the maximum case). */ - if (!maxunder4k) - res->posunder4k = false; - /* Also clear POSUNDER4K if the directive may fail. */ - if (fmtres.mayfail) - res->posunder4k = false; - - if (!warned - /* Only warn at level 2. */ - && warn_level > 1 - /* Only warn for string functions. */ - && info.is_string_func () - && (!minunder4k - || (!maxunder4k && fmtres.range.max < HOST_WIDE_INT_MAX))) - { - /* The directive output may be longer than the maximum required - to be handled by an implementation according to 7.21.6.1, p15 - of C11. Warn on this only at level 2 but remember this and - prevent folding the return value when done. This allows for - the possibility of the actual libc call failing due to ENOMEM - (like Glibc does with very large precision or width). - Issue the "may exceed" warning only for string functions and - not for fprintf or printf. */ - - if (fmtres.range.min == fmtres.range.max) - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output of %wu bytes exceeds " - "minimum required size of 4095", dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min); - else if (!minunder4k) - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output between %wu and %wu " - "bytes exceeds minimum required size of 4095", - dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min, fmtres.range.max); - else if (!info.retval_used () && info.is_string_func ()) - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output between %wu and %wu " - "bytes may exceed minimum required size of " - "4095", - dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min, fmtres.range.max); - } - - /* Has the likely and maximum directive output exceeded INT_MAX? */ - bool likelyximax = *dir.beg && res->range.likely > target_int_max (); - /* Don't consider the maximum to be in excess when it's the result - of a string of unknown length (i.e., whose maximum has been set - to be greater than or equal to HOST_WIDE_INT_MAX. */ - bool maxximax = (*dir.beg - && res->range.max > target_int_max () - && res->range.max < HOST_WIDE_INT_MAX); - - if (!warned - /* Warn for the likely output size at level 1. */ - && (likelyximax - /* But only warn for the maximum at level 2. */ - || (warn_level > 1 - && maxximax - && fmtres.range.max < HOST_WIDE_INT_MAX))) - { - if (fmtres.range.min > target_int_max ()) - { - /* The directive output exceeds INT_MAX bytes. */ - if (fmtres.range.min == fmtres.range.max) - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output of %wu bytes exceeds " - "%<INT_MAX%>", dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min); - else - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output between %wu and " - "%wu bytes exceeds %<INT_MAX%>", dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min, fmtres.range.max); - } - else if (res->range.min > target_int_max ()) - { - /* The directive output is under INT_MAX but causes the result - to exceed INT_MAX bytes. */ - if (fmtres.range.min == fmtres.range.max) - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output of %wu bytes causes " - "result to exceed %<INT_MAX%>", dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min); - else - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output between %wu and " - "%wu bytes causes result to exceed %<INT_MAX%>", - dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min, fmtres.range.max); - } - else if ((!info.retval_used () || !info.bounded) - && (info.is_string_func ())) - /* Warn for calls to string functions that either aren't bounded - (sprintf) or whose return value isn't used. */ - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive output between %wu and " - "%wu bytes may cause result to exceed " - "%<INT_MAX%>", dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg), - fmtres.range.min, fmtres.range.max); - } - - if (!warned && fmtres.nonstr) - { - warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (), - "%<%.*s%> directive argument is not a nul-terminated " - "string", - dirlen, - target_to_host (hostdir, sizeof hostdir, dir.beg)); - if (warned && DECL_P (fmtres.nonstr)) - inform (DECL_SOURCE_LOCATION (fmtres.nonstr), - "referenced argument declared here"); - return false; - } - - if (warned && fmtres.range.min < fmtres.range.likely - && fmtres.range.likely < fmtres.range.max) - inform_n (info.fmtloc, fmtres.range.likely, - "assuming directive output of %wu byte", - "assuming directive output of %wu bytes", - fmtres.range.likely); - - if (warned && fmtres.argmin) - { - if (fmtres.argmin == fmtres.argmax) - inform (info.fmtloc, "directive argument %qE", fmtres.argmin); - else if (fmtres.knownrange) - inform (info.fmtloc, "directive argument in the range [%E, %E]", - fmtres.argmin, fmtres.argmax); - else - inform (info.fmtloc, - "using the range [%E, %E] for directive argument", - fmtres.argmin, fmtres.argmax); - } - - res->warned |= warned; - - if (!dir.beg[0] && res->warned) - { - location_t callloc = gimple_location (info.callstmt); - - unsigned HOST_WIDE_INT min = res->range.min; - unsigned HOST_WIDE_INT max = res->range.max; - - if (info.objsize < HOST_WIDE_INT_MAX) - { - /* If a warning has been issued for buffer overflow or truncation - help the user figure out how big a buffer they need. */ - - if (min == max) - inform_n (callloc, min, - "%qE output %wu byte into a destination of size %wu", - "%qE output %wu bytes into a destination of size %wu", - info.func, min, info.objsize); - else if (max < HOST_WIDE_INT_MAX) - inform (callloc, - "%qE output between %wu and %wu bytes into " - "a destination of size %wu", - info.func, min, max, info.objsize); - else if (min < res->range.likely && res->range.likely < max) - inform (callloc, - "%qE output %wu or more bytes (assuming %wu) into " - "a destination of size %wu", - info.func, min, res->range.likely, info.objsize); - else - inform (callloc, - "%qE output %wu or more bytes into a destination of size " - "%wu", - info.func, min, info.objsize); - } - else if (!info.is_string_func ()) - { - /* If the warning is for a file function like fprintf - of printf with no destination size just print the computed - result. */ - if (min == max) - inform_n (callloc, min, - "%qE output %wu byte", "%qE output %wu bytes", - info.func, min); - else if (max < HOST_WIDE_INT_MAX) - inform (callloc, - "%qE output between %wu and %wu bytes", - info.func, min, max); - else if (min < res->range.likely && res->range.likely < max) - inform (callloc, - "%qE output %wu or more bytes (assuming %wu)", - info.func, min, res->range.likely); - else - inform (callloc, - "%qE output %wu or more bytes", - info.func, min); - } - } - - if (dump_file && *dir.beg) - { - fprintf (dump_file, - " Result: " - HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ", " - HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC " (" - HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ", " - HOST_WIDE_INT_PRINT_DEC ", " HOST_WIDE_INT_PRINT_DEC ")\n", - fmtres.range.min, fmtres.range.likely, - fmtres.range.max, fmtres.range.unlikely, - res->range.min, res->range.likely, - res->range.max, res->range.unlikely); - } - - return true; -} - -/* Parse a format directive in function call described by INFO starting - at STR and populate DIR structure. Bump up *ARGNO by the number of - arguments extracted for the directive. Return the length of - the directive. */ - -static size_t -parse_directive (call_info &info, - directive &dir, format_result *res, - const char *str, unsigned *argno, - range_query *query) -{ - const char *pcnt = strchr (str, target_percent); - dir.beg = str; - - if (size_t len = pcnt ? pcnt - str : *str ? strlen (str) : 1) - { - /* This directive is either a plain string or the terminating nul - (which isn't really a directive but it simplifies things to - handle it as if it were). */ - dir.len = len; - dir.fmtfunc = format_plain; - - if (dump_file) - { - fprintf (dump_file, " Directive %u at offset " - HOST_WIDE_INT_PRINT_UNSIGNED ": \"%.*s\", " - "length = " HOST_WIDE_INT_PRINT_UNSIGNED "\n", - dir.dirno, - (unsigned HOST_WIDE_INT)(size_t)(dir.beg - info.fmtstr), - (int)dir.len, dir.beg, (unsigned HOST_WIDE_INT) dir.len); - } - - return len - !*str; - } - - /* Set the directive argument's number to correspond to its position - in the formatted function call's argument list. */ - dir.argno = *argno; - - const char *pf = pcnt + 1; - - /* POSIX numbered argument index or zero when none. */ - HOST_WIDE_INT dollar = 0; - - /* With and precision. -1 when not specified, HOST_WIDE_INT_MIN - when given by a va_list argument, and a non-negative value - when specified in the format string itself. */ - HOST_WIDE_INT width = -1; - HOST_WIDE_INT precision = -1; - - /* Pointers to the beginning of the width and precision decimal - string (if any) within the directive. */ - const char *pwidth = 0; - const char *pprec = 0; - - /* When the value of the decimal string that specifies width or - precision is out of range, points to the digit that causes - the value to exceed the limit. */ - const char *werange = NULL; - const char *perange = NULL; - - /* Width specified via the asterisk. Need not be INTEGER_CST. - For vararg functions set to void_node. */ - tree star_width = NULL_TREE; - - /* Width specified via the asterisk. Need not be INTEGER_CST. - For vararg functions set to void_node. */ - tree star_precision = NULL_TREE; - - if (ISDIGIT (target_to_host (*pf))) - { - /* This could be either a POSIX positional argument, the '0' - flag, or a width, depending on what follows. Store it as - width and sort it out later after the next character has - been seen. */ - pwidth = pf; - width = target_strtowi (&pf, &werange); - } - else if (target_to_host (*pf) == '*') - { - /* Similarly to the block above, this could be either a POSIX - positional argument or a width, depending on what follows. */ - if (*argno < gimple_call_num_args (info.callstmt)) - star_width = gimple_call_arg (info.callstmt, (*argno)++); - else - star_width = void_node; - ++pf; - } - - if (target_to_host (*pf) == '$') - { - /* Handle the POSIX dollar sign which references the 1-based - positional argument number. */ - if (width != -1) - dollar = width + info.argidx; - else if (star_width - && TREE_CODE (star_width) == INTEGER_CST - && (TYPE_PRECISION (TREE_TYPE (star_width)) - <= TYPE_PRECISION (integer_type_node))) - dollar = width + tree_to_shwi (star_width); - - /* Bail when the numbered argument is out of range (it will - have already been diagnosed by -Wformat). */ - if (dollar == 0 - || dollar == (int)info.argidx - || dollar > gimple_call_num_args (info.callstmt)) - return false; - - --dollar; - - star_width = NULL_TREE; - width = -1; - ++pf; - } - - if (dollar || !star_width) - { - if (width != -1) - { - if (width == 0) - { - /* The '0' that has been interpreted as a width above is - actually a flag. Reset HAVE_WIDTH, set the '0' flag, - and continue processing other flags. */ - width = -1; - dir.set_flag ('0'); - } - else if (!dollar) - { - /* (Non-zero) width has been seen. The next character - is either a period or a digit. */ - goto start_precision; - } - } - /* When either '$' has been seen, or width has not been seen, - the next field is the optional flags followed by an optional - width. */ - for ( ; ; ) { - switch (target_to_host (*pf)) - { - case ' ': - case '0': - case '+': - case '-': - case '#': - dir.set_flag (target_to_host (*pf++)); - break; - - default: - goto start_width; - } - } - - start_width: - if (ISDIGIT (target_to_host (*pf))) - { - werange = 0; - pwidth = pf; - width = target_strtowi (&pf, &werange); - } - else if (target_to_host (*pf) == '*') - { - if (*argno < gimple_call_num_args (info.callstmt)) - star_width = gimple_call_arg (info.callstmt, (*argno)++); - else - { - /* This is (likely) a va_list. It could also be an invalid - call with insufficient arguments. */ - star_width = void_node; - } - ++pf; - } - else if (target_to_host (*pf) == '\'') - { - /* The POSIX apostrophe indicating a numeric grouping - in the current locale. Even though it's possible to - estimate the upper bound on the size of the output - based on the number of digits it probably isn't worth - continuing. */ - return 0; - } - } - - start_precision: - if (target_to_host (*pf) == '.') - { - ++pf; - - if (ISDIGIT (target_to_host (*pf))) - { - pprec = pf; - precision = target_strtowi (&pf, &perange); - } - else if (target_to_host (*pf) == '*') - { - if (*argno < gimple_call_num_args (info.callstmt)) - star_precision = gimple_call_arg (info.callstmt, (*argno)++); - else - { - /* This is (likely) a va_list. It could also be an invalid - call with insufficient arguments. */ - star_precision = void_node; - } - ++pf; - } - else - { - /* The decimal precision or the asterisk are optional. - When neither is specified it's taken to be zero. */ - precision = 0; - } - } - - switch (target_to_host (*pf)) - { - case 'h': - if (target_to_host (pf[1]) == 'h') - { - ++pf; - dir.modifier = FMT_LEN_hh; - } - else - dir.modifier = FMT_LEN_h; - ++pf; - break; - - case 'j': - dir.modifier = FMT_LEN_j; - ++pf; - break; - - case 'L': - dir.modifier = FMT_LEN_L; - ++pf; - break; - - case 'l': - if (target_to_host (pf[1]) == 'l') - { - ++pf; - dir.modifier = FMT_LEN_ll; - } - else - dir.modifier = FMT_LEN_l; - ++pf; - break; - - case 't': - dir.modifier = FMT_LEN_t; - ++pf; - break; - - case 'z': - dir.modifier = FMT_LEN_z; - ++pf; - break; - } - - switch (target_to_host (*pf)) - { - /* Handle a sole '%' character the same as "%%" but since it's - undefined prevent the result from being folded. */ - case '\0': - --pf; - res->range.min = res->range.max = HOST_WIDE_INT_M1U; - /* FALLTHRU */ - case '%': - dir.fmtfunc = format_percent; - break; - - case 'a': - case 'A': - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - res->floating = true; - dir.fmtfunc = format_floating; - break; - - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - dir.fmtfunc = format_integer; - break; - - case 'p': - /* The %p output is implementation-defined. It's possible - to determine this format but due to extensions (especially - those of the Linux kernel -- see bug 78512) the first %p - in the format string disables any further processing. */ - return false; - - case 'n': - /* %n has side-effects even when nothing is actually printed to - any buffer. */ - info.nowrite = false; - dir.fmtfunc = format_none; - break; - - case 'C': - case 'c': - /* POSIX wide character and C/POSIX narrow character. */ - dir.fmtfunc = format_character; - break; - - case 'S': - case 's': - /* POSIX wide string and C/POSIX narrow character string. */ - dir.fmtfunc = format_string; - break; - - default: - /* Unknown conversion specification. */ - return 0; - } - - dir.specifier = target_to_host (*pf++); - - /* Store the length of the format directive. */ - dir.len = pf - pcnt; - - /* Buffer for the directive in the host character set (used when - the source character set is different). */ - char hostdir[32]; - - if (star_width) - { - if (INTEGRAL_TYPE_P (TREE_TYPE (star_width))) - dir.set_width (star_width, query); - else - { - /* Width specified by a va_list takes on the range [0, -INT_MIN] - (width is the absolute value of that specified). */ - dir.width[0] = 0; - dir.width[1] = target_int_max () + 1; - } - } - else - { - if (width == HOST_WIDE_INT_MAX && werange) - { - size_t begin = dir.beg - info.fmtstr + (pwidth - pcnt); - size_t caret = begin + (werange - pcnt); - size_t end = pf - info.fmtstr - 1; - - /* Create a location for the width part of the directive, - pointing the caret at the first out-of-range digit. */ - substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format), - caret, begin, end); - - fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (), - "%<%.*s%> directive width out of range", (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg)); - } - - dir.set_width (width); - } - - if (star_precision) - { - if (INTEGRAL_TYPE_P (TREE_TYPE (star_precision))) - dir.set_precision (star_precision, query); - else - { - /* Precision specified by a va_list takes on the range [-1, INT_MAX] - (unlike width, negative precision is ignored). */ - dir.prec[0] = -1; - dir.prec[1] = target_int_max (); - } - } - else - { - if (precision == HOST_WIDE_INT_MAX && perange) - { - size_t begin = dir.beg - info.fmtstr + (pprec - pcnt) - 1; - size_t caret = dir.beg - info.fmtstr + (perange - pcnt) - 1; - size_t end = pf - info.fmtstr - 2; - - /* Create a location for the precision part of the directive, - including the leading period, pointing the caret at the first - out-of-range digit . */ - substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format), - caret, begin, end); - - fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (), - "%<%.*s%> directive precision out of range", (int) dir.len, - target_to_host (hostdir, sizeof hostdir, dir.beg)); - } - - dir.set_precision (precision); - } - - /* Extract the argument if the directive takes one and if it's - available (e.g., the function doesn't take a va_list). Treat - missing arguments the same as va_list, even though they will - have likely already been diagnosed by -Wformat. */ - if (dir.specifier != '%' - && *argno < gimple_call_num_args (info.callstmt)) - dir.arg = gimple_call_arg (info.callstmt, dollar ? dollar : (*argno)++); - - if (dump_file) - { - fprintf (dump_file, - " Directive %u at offset " HOST_WIDE_INT_PRINT_UNSIGNED - ": \"%.*s\"", - dir.dirno, - (unsigned HOST_WIDE_INT)(size_t)(dir.beg - info.fmtstr), - (int)dir.len, dir.beg); - if (star_width) - { - if (dir.width[0] == dir.width[1]) - fprintf (dump_file, ", width = " HOST_WIDE_INT_PRINT_DEC, - dir.width[0]); - else - fprintf (dump_file, - ", width in range [" HOST_WIDE_INT_PRINT_DEC - ", " HOST_WIDE_INT_PRINT_DEC "]", - dir.width[0], dir.width[1]); - } - - if (star_precision) - { - if (dir.prec[0] == dir.prec[1]) - fprintf (dump_file, ", precision = " HOST_WIDE_INT_PRINT_DEC, - dir.prec[0]); - else - fprintf (dump_file, - ", precision in range [" HOST_WIDE_INT_PRINT_DEC - HOST_WIDE_INT_PRINT_DEC "]", - dir.prec[0], dir.prec[1]); - } - fputc ('\n', dump_file); - } - - return dir.len; -} - -/* Diagnose overlap between destination and %s directive arguments. */ - -static void -maybe_warn_overlap (call_info &info, format_result *res) -{ - /* Two vectors of 1-based indices corresponding to either certainly - or possibly aliasing arguments. */ - auto_vec<int, 16> aliasarg[2]; - - /* Go through the array of potentially aliasing directives and collect - argument numbers of those that do or may overlap the destination - object given the full result. */ - for (unsigned i = 0; i != res->alias_count; ++i) - { - const format_result::alias_info &alias = res->aliases[i]; - - enum { possible = -1, none = 0, certain = 1 } overlap = none; - - /* If the precision is zero there is no overlap. (This only - considers %s directives and ignores %n.) */ - if (alias.dir.prec[0] == 0 && alias.dir.prec[1] == 0) - continue; - - if (alias.offset == HOST_WIDE_INT_MAX - || info.dst_offset == HOST_WIDE_INT_MAX) - overlap = possible; - else if (alias.offset == info.dst_offset) - overlap = alias.dir.prec[0] == 0 ? possible : certain; - else - { - /* Determine overlap from the range of output and offsets - into the same destination as the source, and rule out - impossible overlap. */ - unsigned HOST_WIDE_INT albeg = alias.offset; - unsigned HOST_WIDE_INT dstbeg = info.dst_offset; - - unsigned HOST_WIDE_INT alend = albeg + alias.range.min; - unsigned HOST_WIDE_INT dstend = dstbeg + res->range.min - 1; - - if ((albeg <= dstbeg && alend > dstbeg) - || (albeg >= dstbeg && albeg < dstend)) - overlap = certain; - else - { - alend = albeg + alias.range.max; - if (alend < albeg) - alend = HOST_WIDE_INT_M1U; - - dstend = dstbeg + res->range.max - 1; - if (dstend < dstbeg) - dstend = HOST_WIDE_INT_M1U; - - if ((albeg >= dstbeg && albeg <= dstend) - || (alend >= dstbeg && alend <= dstend)) - overlap = possible; - } - } - - if (overlap == none) - continue; - - /* Append the 1-based argument number. */ - aliasarg[overlap != certain].safe_push (alias.dir.argno + 1); - - /* Disable any kind of optimization. */ - res->range.unlikely = HOST_WIDE_INT_M1U; - } - - tree arg0 = gimple_call_arg (info.callstmt, 0); - location_t loc = gimple_location (info.callstmt); - - bool aliaswarn = false; - - unsigned ncertain = aliasarg[0].length (); - unsigned npossible = aliasarg[1].length (); - if (ncertain && npossible) - { - /* If there are multiple arguments that overlap, some certainly - and some possibly, handle both sets in a single diagnostic. */ - aliaswarn - = warning_at (loc, OPT_Wrestrict, - "%qE arguments %Z and maybe %Z overlap destination " - "object %qE", - info.func, aliasarg[0].address (), ncertain, - aliasarg[1].address (), npossible, - info.dst_origin); - } - else if (ncertain) - { - /* There is only one set of two or more arguments and they all - certainly overlap the destination. */ - aliaswarn - = warning_n (loc, OPT_Wrestrict, ncertain, - "%qE argument %Z overlaps destination object %qE", - "%qE arguments %Z overlap destination object %qE", - info.func, aliasarg[0].address (), ncertain, - info.dst_origin); - } - else if (npossible) - { - /* There is only one set of two or more arguments and they all - may overlap (but need not). */ - aliaswarn - = warning_n (loc, OPT_Wrestrict, npossible, - "%qE argument %Z may overlap destination object %qE", - "%qE arguments %Z may overlap destination object %qE", - info.func, aliasarg[1].address (), npossible, - info.dst_origin); - } - - if (aliaswarn) - { - res->warned = true; - - if (info.dst_origin != arg0) - { - /* If its location is different from the first argument of the call - point either at the destination object itself or at the expression - that was used to determine the overlap. */ - loc = (DECL_P (info.dst_origin) - ? DECL_SOURCE_LOCATION (info.dst_origin) - : EXPR_LOCATION (info.dst_origin)); - if (loc != UNKNOWN_LOCATION) - inform (loc, - "destination object referenced by %<restrict%>-qualified " - "argument 1 was declared here"); - } - } -} - -/* Compute the length of the output resulting from the call to a formatted - output function described by INFO and store the result of the call in - *RES. Issue warnings for detected past the end writes. Return true - if the complete format string has been processed and *RES can be relied - on, false otherwise (e.g., when a unknown or unhandled directive was seen - that caused the processing to be terminated early). */ - -static bool -compute_format_length (call_info &info, format_result *res, range_query *query) -{ - if (dump_file) - { - location_t callloc = gimple_location (info.callstmt); - fprintf (dump_file, "%s:%i: ", - LOCATION_FILE (callloc), LOCATION_LINE (callloc)); - print_generic_expr (dump_file, info.func, dump_flags); - - fprintf (dump_file, - ": objsize = " HOST_WIDE_INT_PRINT_UNSIGNED - ", fmtstr = \"%s\"\n", - info.objsize, info.fmtstr); - } - - /* Reset the minimum and maximum byte counters. */ - res->range.min = res->range.max = 0; - - /* No directive has been seen yet so the length of output is bounded - by the known range [0, 0] (with no conversion resulting in a failure - or producing more than 4K bytes) until determined otherwise. */ - res->knownrange = true; - res->floating = false; - res->warned = false; - - /* 1-based directive counter. */ - unsigned dirno = 1; - - /* The variadic argument counter. */ - unsigned argno = info.argidx; - - bool success = true; - - for (const char *pf = info.fmtstr; ; ++dirno) - { - directive dir (&info, dirno); - - size_t n = parse_directive (info, dir, res, pf, &argno, query); - - /* Return failure if the format function fails. */ - if (!format_directive (info, res, dir, query)) - return false; - - /* Return success when the directive is zero bytes long and it's - the last thing in the format string (i.e., it's the terminating - nul, which isn't really a directive but handling it as one makes - things simpler). */ - if (!n) - { - success = *pf == '\0'; - break; - } - - pf += n; - } - - maybe_warn_overlap (info, res); - - /* The complete format string was processed (with or without warnings). */ - return success; -} - -/* Return the size of the object referenced by the expression DEST in - statement STMT, if available, or the maximum possible size otherwise. */ - -static unsigned HOST_WIDE_INT -get_destination_size (tree dest, gimple *stmt, pointer_query &ptr_qry) -{ - /* When there is no destination return the maximum. */ - if (!dest) - return HOST_WIDE_INT_MAX; - - /* Use compute_objsize to determine the size of the destination object. */ - access_ref aref; - if (!ptr_qry.get_ref (dest, stmt, &aref)) - return HOST_WIDE_INT_MAX; - - offset_int remsize = aref.size_remaining (); - if (!wi::fits_uhwi_p (remsize)) - return HOST_WIDE_INT_MAX; - - return remsize.to_uhwi (); -} - -/* Return true if the call described by INFO with result RES safe to - optimize (i.e., no undefined behavior), and set RETVAL to the range - of its return values. */ - -static bool -is_call_safe (const call_info &info, - const format_result &res, bool under4k, - unsigned HOST_WIDE_INT retval[2]) -{ - if (under4k && !res.posunder4k) - return false; - - /* The minimum return value. */ - retval[0] = res.range.min; - - /* The maximum return value is in most cases bounded by RES.RANGE.MAX - but in cases involving multibyte characters could be as large as - RES.RANGE.UNLIKELY. */ - retval[1] - = res.range.unlikely < res.range.max ? res.range.max : res.range.unlikely; - - /* Adjust the number of bytes which includes the terminating nul - to reflect the return value of the function which does not. - Because the valid range of the function is [INT_MIN, INT_MAX], - a valid range before the adjustment below is [0, INT_MAX + 1] - (the functions only return negative values on error or undefined - behavior). */ - if (retval[0] <= target_int_max () + 1) - --retval[0]; - if (retval[1] <= target_int_max () + 1) - --retval[1]; - - /* Avoid the return value optimization when the behavior of the call - is undefined either because any directive may have produced 4K or - more of output, or the return value exceeds INT_MAX, or because - the output overflows the destination object (but leave it enabled - when the function is bounded because then the behavior is well- - defined). */ - if (retval[0] == retval[1] - && (info.bounded || retval[0] < info.objsize) - && retval[0] <= target_int_max ()) - return true; - - if ((info.bounded || retval[1] < info.objsize) - && (retval[0] < target_int_max () - && retval[1] < target_int_max ())) - return true; - - if (!under4k && (info.bounded || retval[0] < info.objsize)) - return true; - - return false; -} - -/* Given a suitable result RES of a call to a formatted output function - described by INFO, substitute the result for the return value of - the call. The result is suitable if the number of bytes it represents - is known and exact. A result that isn't suitable for substitution may - have its range set to the range of return values, if that is known. - Return true if the call is removed and gsi_next should not be performed - in the caller. */ - -static bool -try_substitute_return_value (gimple_stmt_iterator *gsi, - const call_info &info, - const format_result &res) -{ - tree lhs = gimple_get_lhs (info.callstmt); - - /* Set to true when the entire call has been removed. */ - bool removed = false; - - /* The minimum and maximum return value. */ - unsigned HOST_WIDE_INT retval[2] = {0}; - bool safe = is_call_safe (info, res, true, retval); - - if (safe - && retval[0] == retval[1] - /* Not prepared to handle possibly throwing calls here; they shouldn't - appear in non-artificial testcases, except when the __*_chk routines - are badly declared. */ - && !stmt_ends_bb_p (info.callstmt)) - { - tree cst = build_int_cst (lhs ? TREE_TYPE (lhs) : integer_type_node, - retval[0]); - - if (lhs == NULL_TREE && info.nowrite) - { - /* Remove the call to the bounded function with a zero size - (e.g., snprintf(0, 0, "%i", 123)) if there is no lhs. */ - unlink_stmt_vdef (info.callstmt); - gsi_remove (gsi, true); - removed = true; - } - else if (info.nowrite) - { - /* Replace the call to the bounded function with a zero size - (e.g., snprintf(0, 0, "%i", 123) with the constant result - of the function. */ - gimplify_and_update_call_from_tree (gsi, cst); - gimple *callstmt = gsi_stmt (*gsi); - update_stmt (callstmt); - } - else if (lhs) - { - /* Replace the left-hand side of the call with the constant - result of the formatted function. */ - gimple_call_set_lhs (info.callstmt, NULL_TREE); - gimple *g = gimple_build_assign (lhs, cst); - gsi_insert_after (gsi, g, GSI_NEW_STMT); - update_stmt (info.callstmt); - } - - if (dump_file) - { - if (removed) - fprintf (dump_file, " Removing call statement."); - else - { - fprintf (dump_file, " Substituting "); - print_generic_expr (dump_file, cst, dump_flags); - fprintf (dump_file, " for %s.\n", - info.nowrite ? "statement" : "return value"); - } - } - } - else if (lhs && types_compatible_p (TREE_TYPE (lhs), integer_type_node)) - { - bool setrange = false; - - if (safe - && (info.bounded || retval[1] < info.objsize) - && (retval[0] < target_int_max () - && retval[1] < target_int_max ())) - { - /* If the result is in a valid range bounded by the size of - the destination set it so that it can be used for subsequent - optimizations. */ - int prec = TYPE_PRECISION (integer_type_node); - - wide_int min = wi::shwi (retval[0], prec); - wide_int max = wi::shwi (retval[1], prec); - set_range_info (lhs, VR_RANGE, min, max); - - setrange = true; - } - - if (dump_file) - { - const char *inbounds - = (retval[0] < info.objsize - ? (retval[1] < info.objsize - ? "in" : "potentially out-of") - : "out-of"); - - const char *what = setrange ? "Setting" : "Discarding"; - if (retval[0] != retval[1]) - fprintf (dump_file, - " %s %s-bounds return value range [" - HOST_WIDE_INT_PRINT_UNSIGNED ", " - HOST_WIDE_INT_PRINT_UNSIGNED "].\n", - what, inbounds, retval[0], retval[1]); - else - fprintf (dump_file, " %s %s-bounds return value " - HOST_WIDE_INT_PRINT_UNSIGNED ".\n", - what, inbounds, retval[0]); - } - } - - if (dump_file) - fputc ('\n', dump_file); - - return removed; -} - -/* Try to simplify a s{,n}printf call described by INFO with result - RES by replacing it with a simpler and presumably more efficient - call (such as strcpy). */ - -static bool -try_simplify_call (gimple_stmt_iterator *gsi, - const call_info &info, - const format_result &res) -{ - unsigned HOST_WIDE_INT dummy[2]; - if (!is_call_safe (info, res, info.retval_used (), dummy)) - return false; - - switch (info.fncode) - { - case BUILT_IN_SNPRINTF: - return gimple_fold_builtin_snprintf (gsi); - - case BUILT_IN_SPRINTF: - return gimple_fold_builtin_sprintf (gsi); - - default: - ; - } - - return false; -} - -/* Return the zero-based index of the format string argument of a printf - like function and set *IDX_ARGS to the first format argument. When - no such index exists return UINT_MAX. */ - -static unsigned -get_user_idx_format (tree fndecl, unsigned *idx_args) -{ - tree attrs = lookup_attribute ("format", DECL_ATTRIBUTES (fndecl)); - if (!attrs) - attrs = lookup_attribute ("format", TYPE_ATTRIBUTES (TREE_TYPE (fndecl))); - - if (!attrs) - return UINT_MAX; - - attrs = TREE_VALUE (attrs); - - tree archetype = TREE_VALUE (attrs); - if (strcmp ("printf", IDENTIFIER_POINTER (archetype))) - return UINT_MAX; - - attrs = TREE_CHAIN (attrs); - tree fmtarg = TREE_VALUE (attrs); - - attrs = TREE_CHAIN (attrs); - tree elliparg = TREE_VALUE (attrs); - - /* Attribute argument indices are 1-based but we use zero-based. */ - *idx_args = tree_to_uhwi (elliparg) - 1; - return tree_to_uhwi (fmtarg) - 1; -} - -} /* Unnamed namespace. */ - -/* Determine if a GIMPLE call at *GSI is to one of the sprintf-like built-in - functions and if so, handle it. Return true if the call is removed and - gsi_next should not be performed in the caller. */ - -bool -handle_printf_call (gimple_stmt_iterator *gsi, pointer_query &ptr_qry) -{ - init_target_to_host_charmap (); - - call_info info = call_info (); - - info.callstmt = gsi_stmt (*gsi); - info.func = gimple_call_fndecl (info.callstmt); - if (!info.func) - return false; - - /* Format string argument number (valid for all functions). */ - unsigned idx_format = UINT_MAX; - if (gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL)) - info.fncode = DECL_FUNCTION_CODE (info.func); - else - { - unsigned idx_args; - idx_format = get_user_idx_format (info.func, &idx_args); - if (idx_format == UINT_MAX - || idx_format >= gimple_call_num_args (info.callstmt) - || idx_args > gimple_call_num_args (info.callstmt) - || !POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (info.callstmt, - idx_format)))) - return false; - info.fncode = BUILT_IN_NONE; - info.argidx = idx_args; - } - - /* The size of the destination as in snprintf(dest, size, ...). */ - unsigned HOST_WIDE_INT dstsize = HOST_WIDE_INT_M1U; - - /* The size of the destination determined by __builtin_object_size. */ - unsigned HOST_WIDE_INT objsize = HOST_WIDE_INT_M1U; - - /* Zero-based buffer size argument number (snprintf and vsnprintf). */ - unsigned idx_dstsize = UINT_MAX; - - /* Object size argument number (snprintf_chk and vsnprintf_chk). */ - unsigned idx_objsize = UINT_MAX; - - /* Destinaton argument number (valid for sprintf functions only). */ - unsigned idx_dstptr = 0; - - switch (info.fncode) - { - case BUILT_IN_NONE: - // User-defined function with attribute format (printf). - idx_dstptr = -1; - break; - - case BUILT_IN_FPRINTF: - // Signature: - // __builtin_fprintf (FILE*, format, ...) - idx_format = 1; - info.argidx = 2; - idx_dstptr = -1; - break; - - case BUILT_IN_FPRINTF_CHK: - // Signature: - // __builtin_fprintf_chk (FILE*, ost, format, ...) - idx_format = 2; - info.argidx = 3; - idx_dstptr = -1; - break; - - case BUILT_IN_FPRINTF_UNLOCKED: - // Signature: - // __builtin_fprintf_unnlocked (FILE*, format, ...) - idx_format = 1; - info.argidx = 2; - idx_dstptr = -1; - break; - - case BUILT_IN_PRINTF: - // Signature: - // __builtin_printf (format, ...) - idx_format = 0; - info.argidx = 1; - idx_dstptr = -1; - break; - - case BUILT_IN_PRINTF_CHK: - // Signature: - // __builtin_printf_chk (ost, format, ...) - idx_format = 1; - info.argidx = 2; - idx_dstptr = -1; - break; - - case BUILT_IN_PRINTF_UNLOCKED: - // Signature: - // __builtin_printf (format, ...) - idx_format = 0; - info.argidx = 1; - idx_dstptr = -1; - break; - - case BUILT_IN_SPRINTF: - // Signature: - // __builtin_sprintf (dst, format, ...) - idx_format = 1; - info.argidx = 2; - break; - - case BUILT_IN_SPRINTF_CHK: - // Signature: - // __builtin___sprintf_chk (dst, ost, objsize, format, ...) - idx_objsize = 2; - idx_format = 3; - info.argidx = 4; - break; - - case BUILT_IN_SNPRINTF: - // Signature: - // __builtin_snprintf (dst, size, format, ...) - idx_dstsize = 1; - idx_format = 2; - info.argidx = 3; - info.bounded = true; - break; - - case BUILT_IN_SNPRINTF_CHK: - // Signature: - // __builtin___snprintf_chk (dst, size, ost, objsize, format, ...) - idx_dstsize = 1; - idx_objsize = 3; - idx_format = 4; - info.argidx = 5; - info.bounded = true; - break; - - case BUILT_IN_VFPRINTF: - // Signature: - // __builtin_vprintf (FILE*, format, va_list) - idx_format = 1; - info.argidx = -1; - idx_dstptr = -1; - break; - - case BUILT_IN_VFPRINTF_CHK: - // Signature: - // __builtin___vfprintf_chk (FILE*, ost, format, va_list) - idx_format = 2; - info.argidx = -1; - idx_dstptr = -1; - break; - - case BUILT_IN_VPRINTF: - // Signature: - // __builtin_vprintf (format, va_list) - idx_format = 0; - info.argidx = -1; - idx_dstptr = -1; - break; - - case BUILT_IN_VPRINTF_CHK: - // Signature: - // __builtin___vprintf_chk (ost, format, va_list) - idx_format = 1; - info.argidx = -1; - idx_dstptr = -1; - break; - - case BUILT_IN_VSNPRINTF: - // Signature: - // __builtin_vsprintf (dst, size, format, va) - idx_dstsize = 1; - idx_format = 2; - info.argidx = -1; - info.bounded = true; - break; - - case BUILT_IN_VSNPRINTF_CHK: - // Signature: - // __builtin___vsnprintf_chk (dst, size, ost, objsize, format, va) - idx_dstsize = 1; - idx_objsize = 3; - idx_format = 4; - info.argidx = -1; - info.bounded = true; - break; - - case BUILT_IN_VSPRINTF: - // Signature: - // __builtin_vsprintf (dst, format, va) - idx_format = 1; - info.argidx = -1; - break; - - case BUILT_IN_VSPRINTF_CHK: - // Signature: - // __builtin___vsprintf_chk (dst, ost, objsize, format, va) - idx_format = 3; - idx_objsize = 2; - info.argidx = -1; - break; - - default: - return false; - } - - /* Set the global warning level for this function. */ - warn_level = info.bounded ? warn_format_trunc : warn_format_overflow; - - /* For all string functions the first argument is a pointer to - the destination. */ - tree dstptr = (idx_dstptr < gimple_call_num_args (info.callstmt) - ? gimple_call_arg (info.callstmt, 0) : NULL_TREE); - - info.format = gimple_call_arg (info.callstmt, idx_format); - - /* True when the destination size is constant as opposed to the lower - or upper bound of a range. */ - bool dstsize_cst_p = true; - bool posunder4k = true; - - if (idx_dstsize == UINT_MAX) - { - /* For non-bounded functions like sprintf, determine the size - of the destination from the object or pointer passed to it - as the first argument. */ - dstsize = get_destination_size (dstptr, info.callstmt, ptr_qry); - } - else if (tree size = gimple_call_arg (info.callstmt, idx_dstsize)) - { - /* For bounded functions try to get the size argument. */ - - if (TREE_CODE (size) == INTEGER_CST) - { - dstsize = tree_to_uhwi (size); - /* No object can be larger than SIZE_MAX bytes (half the address - space) on the target. - The functions are defined only for output of at most INT_MAX - bytes. Specifying a bound in excess of that limit effectively - defeats the bounds checking (and on some implementations such - as Solaris cause the function to fail with EINVAL). */ - if (dstsize > target_size_max () / 2) - { - /* Avoid warning if -Wstringop-overflow is specified since - it also warns for the same thing though only for the - checking built-ins. */ - if ((idx_objsize == UINT_MAX - || !warn_stringop_overflow)) - warning_at (gimple_location (info.callstmt), info.warnopt (), - "specified bound %wu exceeds maximum object size " - "%wu", - dstsize, target_size_max () / 2); - /* POSIX requires snprintf to fail if DSTSIZE is greater - than INT_MAX. Even though not all POSIX implementations - conform to the requirement, avoid folding in this case. */ - posunder4k = false; - } - else if (dstsize > target_int_max ()) - { - warning_at (gimple_location (info.callstmt), info.warnopt (), - "specified bound %wu exceeds %<INT_MAX%>", - dstsize); - /* POSIX requires snprintf to fail if DSTSIZE is greater - than INT_MAX. Avoid folding in that case. */ - posunder4k = false; - } - } - else if (TREE_CODE (size) == SSA_NAME) - { - /* Try to determine the range of values of the argument - and use the greater of the two at level 1 and the smaller - of them at level 2. */ - value_range vr; - ptr_qry.rvals->range_of_expr (vr, size, info.callstmt); - - if (!vr.undefined_p ()) - { - tree type = TREE_TYPE (size); - tree tmin = wide_int_to_tree (type, vr.lower_bound ()); - tree tmax = wide_int_to_tree (type, vr.upper_bound ()); - unsigned HOST_WIDE_INT minsize = TREE_INT_CST_LOW (tmin); - unsigned HOST_WIDE_INT maxsize = TREE_INT_CST_LOW (tmax); - dstsize = warn_level < 2 ? maxsize : minsize; - - if (minsize > target_int_max ()) - warning_at (gimple_location (info.callstmt), info.warnopt (), - "specified bound range [%wu, %wu] exceeds " - "%<INT_MAX%>", - minsize, maxsize); - - /* POSIX requires snprintf to fail if DSTSIZE is greater - than INT_MAX. Avoid folding if that's possible. */ - if (maxsize > target_int_max ()) - posunder4k = false; - } - - /* The destination size is not constant. If the function is - bounded (e.g., snprintf) a lower bound of zero doesn't - necessarily imply it can be eliminated. */ - dstsize_cst_p = false; - } - } - - if (idx_objsize != UINT_MAX) - if (tree size = gimple_call_arg (info.callstmt, idx_objsize)) - if (tree_fits_uhwi_p (size)) - objsize = tree_to_uhwi (size); - - if (info.bounded && !dstsize) - { - /* As a special case, when the explicitly specified destination - size argument (to a bounded function like snprintf) is zero - it is a request to determine the number of bytes on output - without actually producing any. Pretend the size is - unlimited in this case. */ - info.objsize = HOST_WIDE_INT_MAX; - info.nowrite = dstsize_cst_p; - } - else - { - /* For calls to non-bounded functions or to those of bounded - functions with a non-zero size, warn if the destination - pointer is null. */ - if (dstptr && integer_zerop (dstptr)) - { - /* This is diagnosed with -Wformat only when the null is a constant - pointer. The warning here diagnoses instances where the pointer - is not constant. */ - location_t loc = gimple_location (info.callstmt); - warning_at (EXPR_LOC_OR_LOC (dstptr, loc), - info.warnopt (), "null destination pointer"); - return false; - } - - /* Set the object size to the smaller of the two arguments - of both have been specified and they're not equal. */ - info.objsize = dstsize < objsize ? dstsize : objsize; - - if (info.bounded - && dstsize < target_size_max () / 2 && objsize < dstsize - /* Avoid warning if -Wstringop-overflow is specified since - it also warns for the same thing though only for the - checking built-ins. */ - && (idx_objsize == UINT_MAX - || !warn_stringop_overflow)) - { - warning_at (gimple_location (info.callstmt), info.warnopt (), - "specified bound %wu exceeds the size %wu " - "of the destination object", dstsize, objsize); - } - } - - /* Determine if the format argument may be null and warn if not - and if the argument is null. */ - if (integer_zerop (info.format) - && gimple_call_builtin_p (info.callstmt, BUILT_IN_NORMAL)) - { - location_t loc = gimple_location (info.callstmt); - warning_at (EXPR_LOC_OR_LOC (info.format, loc), - info.warnopt (), "null format string"); - return false; - } - - info.fmtstr = get_format_string (info.format, &info.fmtloc); - if (!info.fmtstr) - return false; - - if (warn_restrict) - { - /* Compute the origin of the destination pointer and its offset - from the base object/pointer if possible. */ - info.dst_offset = 0; - info.dst_origin = get_origin_and_offset (dstptr, &info.dst_field, - &info.dst_offset); - } - - /* The result is the number of bytes output by the formatted function, - including the terminating NUL. */ - format_result res; - - /* I/O functions with no destination argument (i.e., all forms of fprintf - and printf) may fail under any conditions. Others (i.e., all forms of - sprintf) may only fail under specific conditions determined for each - directive. Clear POSUNDER4K for the former set of functions and set - it to true for the latter (it can only be cleared later, but it is - never set to true again). */ - res.posunder4k = posunder4k && dstptr; - - bool success = compute_format_length (info, &res, ptr_qry.rvals); - if (res.warned) - suppress_warning (info.callstmt, info.warnopt ()); - - /* When optimizing and the printf return value optimization is enabled, - attempt to substitute the computed result for the return value of - the call. Avoid this optimization when -frounding-math is in effect - and the format string contains a floating point directive. */ - bool call_removed = false; - if (success && optimize > 0) - { - /* Save a copy of the iterator pointing at the call. The iterator - may change to point past the call in try_substitute_return_value - but the original value is needed in try_simplify_call. */ - gimple_stmt_iterator gsi_call = *gsi; - - if (flag_printf_return_value - && (!flag_rounding_math || !res.floating)) - call_removed = try_substitute_return_value (gsi, info, res); - - if (!call_removed) - try_simplify_call (&gsi_call, info, res); - } - - return call_removed; -} |