Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2d11d26

Browse files
committed
Create a tool to catch #include omissions that might not result in any
compiler warning, specifically #ifdef or #if defined tests on symbolsthat are defined in a file not included. The results are a bit noisyand require care to interpret, but it's a lot better than no tool at all.
1 parent98bac16 commit2d11d26

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed

‎src/tools/pginclude/README

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ pgcompinclude [-v]
1010
pgrminclude [-v]
1111
remove extra #include's
1212

13+
pgcheckdefines
14+
check for #ifdef tests on symbols defined in files that
15+
weren't included --- this is a necessary sanity check on
16+
pgrminclude!
17+
1318
pgdefinecreate macro calls for all defines in the file (used by
1419
the above routines)
1520

@@ -22,3 +27,4 @@ order would be:
2227
pgrminclude /src/include
2328
pgcompinclude
2429
pgrminclude /
30+
pgcheckdefines

‎src/tools/pginclude/pgcheckdefines

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
#! /usr/bin/perl -w
2+
3+
#
4+
# This script looks for symbols that are referenced in #ifdef or defined()
5+
# tests without having #include'd the file that defines them. Since this
6+
# situation won't necessarily lead to any compiler message, it seems worth
7+
# having an automated check for it. In particular, use this to audit the
8+
# results of pgrminclude!
9+
#
10+
# Usage: configure and build a PG source tree (non-VPATH), then start this
11+
# script at the top level. It's best to enable as many configure options
12+
# as you can, especially --enable-cassert which is known to affect include
13+
# requirements. NB: you MUST use gcc, unless you have another compiler that
14+
# can be persuaded to spit out the names of referenced include files.
15+
#
16+
# The results are necessarily platform-dependent, so use care in interpreting
17+
# them. We try to process all .c files, even those not intended for the
18+
# current platform, so there will be some phony failures.
19+
#
20+
# $PostgreSQL: pgsql/src/tools/pginclude/pgcheckdefines,v 1.1 2006/07/15 03:27:42 tgl Exp $
21+
#
22+
23+
use Cwd;
24+
use File::Basename;
25+
26+
$topdir = cwd();
27+
28+
# Programs to use
29+
$FIND ="find";
30+
$MAKE ="make";
31+
32+
#
33+
# Build arrays of all the .c and .h files in the tree
34+
#
35+
# We ignore .h files under src/include/port/, since only the one exposed as
36+
# src/include/port.h is interesting. (XXX Windows ports have additional
37+
# files there?) Ditto for .h files in src/backend/port/ subdirectories.
38+
# Including these .h files would clutter the list of define'd symbols and
39+
# cause a lot of false-positive results.
40+
#
41+
open PIPE,"$FIND * -type f -name '*.c' |"
42+
ordie"can't fork:$!";
43+
while (<PIPE>) {
44+
chomp;
45+
push@cfiles,$_;
46+
}
47+
close PIPEordie"$FIND failed:$!";
48+
49+
open PIPE,"$FIND * -type f -name '*.h' |"
50+
ordie"can't fork:$!";
51+
while (<PIPE>) {
52+
chomp;
53+
push@hfiles,$_unless
54+
m|^src/include/port/| ||
55+
m|^src/backend/port/\w+/|;
56+
}
57+
close PIPEordie"$FIND failed:$!";
58+
59+
#
60+
# For each .h file, extract all the symbols it #define's, and add them to
61+
# a hash table. To cover the possibility of multiple .h files defining
62+
# the same symbol, we make each hash entry a hash of filenames.
63+
#
64+
foreach$hfile (@hfiles) {
65+
open HFILE,$hfile
66+
ordie"can't open$hfile:$!";
67+
while (<HFILE>) {
68+
if (m/^\s*#\s*define\s+(\w+)/) {
69+
$defines{$1}{$hfile} = 1;
70+
}
71+
}
72+
close HFILE;
73+
}
74+
75+
#
76+
# For each file (both .h and .c), run the compiler to get a list of what
77+
# files it #include's. Then extract all the symbols it tests for defined-ness,
78+
# and check each one against the previously built hashtable.
79+
#
80+
foreach$file (@hfiles,@cfiles) {
81+
($fname,$fpath) = fileparse($file);
82+
chdir$fpathordie"can't chdir to$fpath:$!";
83+
#
84+
# Ask 'make' to parse the makefile so we can get the correct flags to
85+
# use. CPPFLAGS in particular varies for each subdirectory. If we are
86+
# processing a .h file, we might be in a subdirectory that has no
87+
# Makefile, in which case we have to fake it. Note that there seems
88+
# no easy way to prevent make from recursing into subdirectories and
89+
# hence printing multiple definitions --- we keep the last one, which
90+
# should come from the current Makefile.
91+
#
92+
if (-f"Makefile" ||-f"GNUmakefile") {
93+
$MAKECMD ="$MAKE -qp";
94+
}else {
95+
$subdir =$fpath;
96+
chop$subdir;
97+
$top_builddir ="..";
98+
$tmp =$fpath;
99+
while (($tmp = dirname($tmp))ne'.') {
100+
$top_builddir =$top_builddir ."/..";
101+
}
102+
$MAKECMD ="$MAKE -qp 'subdir=$subdir' 'top_builddir=$top_builddir' -f '$top_builddir/src/Makefile.global'";
103+
}
104+
open PIPE,"$MAKECMD |"
105+
ordie"can't fork:$!";
106+
while (<PIPE>) {
107+
if (m/^CPPFLAGS :?= (.*)/) {
108+
$CPPFLAGS =$1;
109+
}elsif (m/^CFLAGS :?= (.*)/) {
110+
$CFLAGS =$1;
111+
}elsif (m/^CFLAGS_SL :?= (.*)/) {
112+
$CFLAGS_SL =$1;
113+
}elsif (m/^PTHREAD_CFLAGS :?= (.*)/) {
114+
$PTHREAD_CFLAGS =$1;
115+
}elsif (m/^CC :?= (.*)/) {
116+
$CC =$1;
117+
}
118+
}
119+
# If make exits with status 1, it's not an error, it just means make
120+
# thinks some files may not be up-to-date. Only complain on status 2.
121+
close PIPE;
122+
die"$MAKE failed in$fpath\n"if$? != 0 &&$? != 256;
123+
124+
# Expand out stuff that might be referenced in CFLAGS
125+
$CFLAGS =~s/\$\(CFLAGS_SL\)/$CFLAGS_SL/;
126+
$CFLAGS =~s/\$\(PTHREAD_CFLAGS\)/$PTHREAD_CFLAGS/;
127+
128+
#
129+
# Run the compiler (which had better be gcc) to get the inclusions.
130+
# "gcc -H" reports inclusions on stderr as "... filename" where the
131+
# number of dots varies according to nesting depth.
132+
#
133+
@includes = ();
134+
$COMPILE ="$CC$CPPFLAGS$CFLAGS -H -E$fname";
135+
open PIPE,"$COMPILE 2>&1 >/dev/null |"
136+
ordie"can't fork:$!";
137+
while (<PIPE>) {
138+
if (m/^\.+ (.*)/) {
139+
$include =$1;
140+
# Ignore system headers (absolute paths); but complain if a
141+
# .c file includes a system header before any PG header.
142+
if ($include =~m|^/|) {
143+
warn"$file includes$include before any Postgres inclusion\n"
144+
if$#includes == -1 &&$file =~m/\.c$/;
145+
next;
146+
}
147+
# Strip any "./" (assume this appears only at front)
148+
$include =~s|^\./||;
149+
# Make path relative to top of tree
150+
$ipath =$fpath;
151+
while ($include =~s|^\.\./||) {
152+
$ipath = dirname($ipath) ."/";
153+
}
154+
$ipath =~s|^\./||;
155+
push@includes,$ipath .$include;
156+
}else {
157+
warn"$CC:$_";
158+
}
159+
}
160+
# The compiler might fail, particularly if we are checking a file that's
161+
# not supposed to be compiled at all on the current platform, so don't
162+
# quit on nonzero status.
163+
close PIPEorwarn"$COMPILE failed in$fpath\n";
164+
165+
#
166+
# Scan the file to find #ifdef, #ifndef, and #if defined() constructs
167+
# We assume #ifdef isn't continued across lines, and that defined(foo)
168+
# isn't split across lines either
169+
#
170+
open FILE,$fname
171+
ordie"can't open$file:$!";
172+
$inif = 0;
173+
while (<FILE>) {
174+
$line =$_;
175+
if ($line =~m/^\s*#\s*ifdef\s+(\w+)/) {
176+
$symbol =$1;
177+
&checkit;
178+
}
179+
if ($line =~m/^\s*#\s*ifndef\s+(\w+)/) {
180+
$symbol =$1;
181+
&checkit;
182+
}
183+
if ($line =~m/^\s*#\s*if\s+/) {
184+
$inif = 1;
185+
}
186+
if ($inif) {
187+
while ($line =~s/\bdefined(\s+|\s*\(\s*)(\w+)//) {
188+
$symbol =$2;
189+
&checkit;
190+
}
191+
if (!($line =~m/\\$/)) {
192+
$inif = 0;
193+
}
194+
}
195+
}
196+
close FILE;
197+
198+
chdir$topdirordie"can't chdir to$topdir:$!";
199+
}
200+
201+
exit 0;
202+
203+
# Check an is-defined reference
204+
subcheckit {
205+
# Ignore if symbol isn't defined in any PG include files
206+
if (!defined$defines{$symbol}) {
207+
return;
208+
}
209+
#
210+
# Try to match source(s) of symbol to the inclusions of the current file
211+
# (including itself). We consider it OK if any one matches.
212+
#
213+
# Note: these tests aren't bulletproof; in theory the inclusion might
214+
# occur after the use of the symbol. Given our normal file layout,
215+
# however, the risk is minimal.
216+
#
217+
foreach$deffile (keys %{$defines{$symbol} }) {
218+
returnif$deffileeq$file;
219+
foreach$reffile (@includes) {
220+
returnif$deffileeq$reffile;
221+
}
222+
}
223+
#
224+
# If current file is a .h file, it's OK for it to assume that one of the
225+
# base headers (postgres.h or postgres_fe.h) has been included.
226+
#
227+
if ($file =~m/\.h$/) {
228+
foreach$deffile (keys %{$defines{$symbol} }) {
229+
returnif$deffileeq'src/include/c.h';
230+
returnif$deffileeq'src/include/postgres.h';
231+
returnif$deffileeq'src/include/postgres_fe.h';
232+
returnif$deffileeq'src/include/pg_config.h';
233+
returnif$deffileeq'src/include/pg_config_manual.h';
234+
}
235+
}
236+
#
237+
@places =keys %{$defines{$symbol} };
238+
print"$file references$symbol, defined in@places\n";
239+
# print "includes: @includes\n";
240+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp