HP HP-UX Web Development Tools User Manual

HP Code Advisor C.02.20 User Guide

HP-UX 11i on HP Integrity and HP 9000 Systems
HP Part Number: 5900-1864 Published: July 2011 Edition: 2
© Copyright 2011 Hewlett-Packard Development Company L.P.
Confidential computer software. Valid license from HP required for possession, use or copying. Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license. The information contained herein is subject to change without notice. The only warranties for HP products and services are set forth in the express warranty statements accompanying such products and services. Nothing herein should be construed as constituting an additional warranty. HP shall not be liable for technical or editorial errors or omissions contained herein. UNIX is a registered trademark of The Open Group.
Itanium® is a trademark of Intel Corporation in the U.S. and other countries.

Contents

About this document......................................................................................5
Intended audience....................................................................................................................5
Document conventions and symbols............................................................................................5
Related information...................................................................................................................5
HP encourages your comments...................................................................................................6
1 Introduction...............................................................................................7
1.1 Cadvise user interface..........................................................................................................7
1.2 Features.............................................................................................................................7
1.2.1 Advanced static code analysis.......................................................................................8
1.2.2 Defect detection..........................................................................................................8
1.2.3 Security vulnerability checks..........................................................................................8
1.2.4 Porting and migration...................................................................................................8
1.2.5 Detection of pre-defined or user-defined coding guideline violation.....................................8
1.2.6 Easy to integrate and use..............................................................................................8
1.2.7 Supported compilers....................................................................................................9
2 Using Cadvise.........................................................................................10
2.1 Getting started..................................................................................................................10
2.1.1 Supported platforms....................................................................................................10
2.1.2 Installing Cadvise.......................................................................................................10
2.2 Steps in using cadvise.......................................................................................................10
2.3 Invoking Cadvise..............................................................................................................11
2.4 Using Cadvise as a wrapper around Compiler or Linker.........................................................12
2.5 Integrating Cadvise with the makefiles and build process.......................................................12
2.6 Enabling different categories of diagnostic messages.............................................................13
2.7 Generating code complexity metrics....................................................................................13
2.8 Detecting violation of pre-defined or user-defined coding guidelines........................................17
3 Using the Program Database (PDB).............................................................19
3.1 PDB options table..............................................................................................................20
3.2 Specifying the PDB location...............................................................................................20
3.3 Deleting PDB....................................................................................................................20
3.4 Disabling locks in PDB operations.......................................................................................20
3.5 Removing object file information from the PDB......................................................................20
3.6 Creating a PDB snapshot at a specified location...................................................................21
3.7 Displaying PDB version......................................................................................................21
4 Using cross-file analysis.............................................................................22
5 Configuring diagnostic messages...............................................................25
5.1 Diagnostic configuration options table..................................................................................25
5.2 Suppressing warnings selectively.........................................................................................25
5.3 Enabling warnings selectively.............................................................................................25
5.4 Interpreting selective warnings as errors...............................................................................26
5.5 Disabling warnings in a macro...........................................................................................26
5.6 Managing warnings in a source file....................................................................................26
6 Generating reports...................................................................................27
6.1 Report generation options table...........................................................................................27
6.2 Generating summary reports..............................................................................................28
6.3 Generating file summary report..........................................................................................28
6.4 Generating detailed report................................................................................................28
6.5 Generating HTML report....................................................................................................29
Contents 3
6.6 Generating XML report......................................................................................................30
6.7 Printing diagnostics with specific diagnostic numbers.............................................................30
6.8 Generating reports based on severity..................................................................................31
6.9 Suppressing diagnostics for specific files..............................................................................31
6.10 Reporting diagnostics from specific files..............................................................................32
6.11 Reporting program complexity metrics................................................................................32
6.12 Generating report for a module.........................................................................................33
6.13 Suppressing report header................................................................................................34
6.14 Modifying the default severity level of a diagnostic...............................................................34
6.15 Generating PDB comparison report....................................................................................34
6.15.1 Generating summary diff report..................................................................................35
6.15.2 Generating detailed diff report..................................................................................35
6.15.2.1 Using -approot option for detailed diff report........................................................37
6.16 Report options file............................................................................................................38
6.17 Generate report for migration related warnings...................................................................39
6.18 Generating consolidated report from multiple PDBs..............................................................39
6.19 Generating PDB diffs with multiple PDBs.............................................................................40
6.20 Recommended process for analyzing the diagnostic messages.............................................40
6.21 Report options interoperability..........................................................................................40
7 Miscellaneous driver options......................................................................42
8 Categories of diagnostics with examples.....................................................45
8.1 Categories of diagnostics table...........................................................................................45
8.2 Detecting generic programming errors.................................................................................45
8.3 Detecting 32-bit to 64-bit migraton issues.............................................................................51
8.4 Detecting endianness migration issues.................................................................................51
8.5 Detecting potential security vulnerabilities.............................................................................52
8.6 Detecting multi-threaded programming issues.......................................................................53
8.7 Detecting potential performance improvement opportunities...................................................54
9 Fixing the warnings by source change.........................................................56
10 Incompatibilities on PA-RISC based systems................................................57
Index.........................................................................................................58
4 Contents

About this document

This document discusses the invocation and usage of HP Code Advisor.

Intended audience

This document is intended for programmers who want to detect the potential errors or warnings in C, C++ applications by using HP Code Advisor.

Document conventions and symbols

Table 1 (page 5) lists the conventions and symbols used in this white paper.
Table 1 Document conventions
ElementConvention
Cross-reference links and email addressesMedium blue text:
Website addressesMedium blue, underlined text
(http://www.hp.com)
Bold font
Monospace font
Monospace, italic font
Monospace, bold font
Key names
Text typed into a GUI element, such as into a box
GUI elements that are clicked or selected, such as menu and list items,
buttons, and check boxes
Text emphasisItalic font
File and directory names
System output
Code
Text typed at the command line
Code variables
Command-line variables
Emphasis of file and directory names, system output, code, and text typed at the command line
CAUTION: Indicates that failure to follow directions can result in damage to equipment or data.
IMPORTANT: Provides clarifying information or specific instructions.
NOTE: Provides additional information.

Related information

The following documents provide additional information about HP Code Advisor:
HP Code Advisor Release Notes
HP Code Advisor Diagnostics Reference Guide
Using HP Code Advisor in Application Builds: [HP Code Advisor] White Paper
HP C/aC++ Features to Improve Developer Productivity - Whitepaper
For additional information, see the HP Code Advisor web page:
http://www.hp.com/go/cadvise
Intended audience 5

HP encourages your comments

HP encourages your comments concerning this document. We are committed to providing documentation that meets your needs. Send any errors found, suggestions for improvement, or compliments to:
cadvise-help@lists.hp.com
6

1 Introduction

HP Code Advisor (cadvise) is a static analysis tool for C and C++ programs. Cadvise reports various programming errors in the source code. This tool enables programmers to identify potential coding errors, porting issues, and security vulnerabilities. Cadvise leverages the advanced analysis capabilities of HP C and HP aC++ compilers available on the HP Integrity systems.
This chapter addresses the following topics:
“Cadvise user interface” (page 7)
“Features” (page 7)

1.1 Cadvise user interface

You can use cadvise through the CLI. Also, you can use the HP Code Advisior GUI, which is part of the Eclipse Remote Development Plugin run remotely on MS-Windows x86 platforms. For more information, see http://www.hp.com/go/eclipse-remotedevplugin.
Cadvise takes C or C++source files as inputs for finding potential errors, security violations, and so on and then stores this information in a Program Database (PDB). The reporting utility helps you generate reports from the PDB in various formats, such as Text, XML, and HTML.
Figure 1 shows the HP Code Advisor components.
Figure 1 Cadvise Components (User Interfaces)

1.2 Features

This section discusses the following major features and benefits of cadvise:
“Advanced static code analysis” (page 8)
“Defect detection” (page 8)
“Security vulnerability checks” (page 8)
“Porting and migration” (page 8)
1.1 Cadvise user interface 7
“Detection of pre-defined or user-defined coding guideline violation” (page 8)
“Easy to integrate and use” (page 8)

1.2.1 Advanced static code analysis

Cadvise is a powerful static code analysis tool that automatically diagnoses various issues in a source program. It improves developer productivity by finding defects at code development time, and leads to more robust and secure software because of fewer escaped defects.
Cadvise leverages advanced cross-file analysis technology from HP compilers. It stores the diagnosed information in a program database. With the built-in knowledge of system APIs, cadvise looks deep into the code and provides helpful warnings with fewer false positives.

1.2.2 Defect detection

Cadvise detects a wide range of coding errors and potential problems such as memory leaks, used after free, double free, array/buffer out of bounds access, illegal pointer access, uninitialized variables, unused variables, format string checks, suspicious conversion and casts, out of range operations, C++ coding style warnings, and so on.

1.2.3 Security vulnerability checks

Security flaws are not only very costly to fix, they can lead to a bad reputation and potential loss of customers. Cadvise detects security vulnerabilities in the source code such as buffer overflows, use of unsafe APIs, use of unsafe file path, unsafe data length argument, unsafe loop exit condition, unsafe use of tainted data, and so on.

1.2.4 Porting and migration

The cadvise also helps you to identify the potential problems in converting applications from 32-bit to 64-bit. The porting help is also available in 32-bit mode. This enables you to evaluate the porting effort before the actual porting begins.
While porting from Linux or Windows? to HP-UX you might encounter problems converting from little-endian to big-endian. cadvise identifies instances where different endianness might produce different results. These instances are very difficult to find manually.
Further, migrating your applications from PA-RISC to HP Integrity systems is much easier with the help of cadvise, which helps you identify the differences between the two compilers and begin porting the code to HP Integrity systems without leaving the familiar PA-RISC environment.

1.2.5 Detection of pre-defined or user-defined coding guideline violation

Cadvise has a built-in coding guidelines checker which diagnoses violations to the coding guidelines and emits appropriate diagnostic messages. You can modify the default set of rules or write your own set of rules to enforce coding guidelines. Cadvise has the appropriate API header files and a set of sample files along with the corresponding Makefile to rebuild the rules library.

1.2.6 Easy to integrate and use

Cadvise is available for HP-UX developers on both HP Integrity and PA-RISC systems as part of C and C++ compiler bundles or as a direct download. The default installation location is /opt/cadvise. Cadvise can be seamlessly integrated with the build process and makefiles. The reporting tool, cadvise report helps you to filter the important warnings without getting lost in tons of trivial warnings.
For example, to use cadvise for a single file, you can simply use the following command:
$ cadvise cc -c hello.c
You can also specify the program database and other options at the command line, as in the following example:
8 Introduction
$ cadvise -pdb ./mypdb +wlint aCC hello.cpp

1.2.7 Supported compilers

Cadvise is shipped and supported with the HP aC++ and HP C compilers on the latest HP Integrity and PA-RISC HP-UX platforms. Cadvise can also be used with GNU gcc and g++ compilers, however it does not support all gcc/g++ built-ins and extensions. Cadvise will emit a parsing error if it comes across an unsupported built-in or extension. If you need support for a specific built-in or extension please send an email to cadvise-help@lists.hp.com.
1.2 Features 9

2 Using Cadvise

This chapter addresses the following topics:
“Getting started” (page 10)
“Steps in using cadvise” (page 10)
“Invoking Cadvise” (page 11)
“Using Cadvise as a wrapper around Compiler or Linker” (page 12)
“Integrating Cadvise with the makefiles and build process” (page 12)
“Enabling different categories of diagnostic messages” (page 13)
“Generating code complexity metrics” (page 13)
“Detecting violation of pre-defined or user-defined coding guidelines” (page 17)

2.1 Getting started

This section addresses the following topics:
“Supported platforms” (page 10)
“Installing Cadvise” (page 10)

2.1.1 Supported platforms

You can install and use cadvise on the following platforms:
HP-UX 11i v3 (B.11.31) PA-RISC (HP 9000) and HP Integrity systems
HP-UX 11i v2 (B.11.23) PA-RISC (HP 9000) and HP Integrity systems
HP-UX 11i v1 (B.11.11) PA-RISC (HP 9000) systems

2.1.2 Installing Cadvise

To install cadvise, complete the following steps:
1. Download cadvise for your platform through the website http://www.hp.com/go/cadvise.
2. Install cadvise using the swinstall command. For more information on using the swinstall
command, see Software Distributor Administration Guide.
Cadvise is installed in the /opt/cadvise/bin/cadvise directory by default.

2.2 Steps in using cadvise

Cadvise is part of an iterative process of building, analyzing, reporting, and removing the potential coding errors in an application, as shown in Figure 2.
10 Using Cadvise
Figure 2 Steps in Using Cadvise
To use cadvise, you perform the following steps:
1. Build the application with the set of compiler or linker options. Ensure that the application
builds successfully.
2. Run cadvise with desired options and create the PDB.
3. Use the reporting utility for generated reports from the PDB in various formats.
4. Make suggested changes based on generated reports. The suggested changes are for defect
prevention, memory leaks, secutity issues, coding guideline violation, and so on.
5. Re-run cadvise on modified sources and generate new reports. Continue making source
changes as long as you receive meaningful data.

2.3 Invoking Cadvise

To invoke cadvise, enter the following command at the HP-UX prompt:
/opt/cadvise/bin/cadvise
2.3 Invoking Cadvise 11
The cadvise command has the following modes of operation:
Analysis mode
Used to analyze and create the Program Database (PDB). To invoke cadvise in this mode, enter the cadvise command in the following format:
cadvise [cadvise-options] compile-cmd [compile-options]
Report mode
Used to create reports. To invoke cadvise in this mode, enter the cadvise command in the following format:
cadvise report [report-options] [-pdb <pdb-name> | logfile]
For information on PDB, see Using the Program Database (PDB) (page 19). The cadvise command is used as a wrapper around the compiler or linker. The cadvise
report option is used to generate reports.

2.4 Using Cadvise as a wrapper around Compiler or Linker

Cadvise is used with the HP C and HP aC++ compilers; GNU gcc and g++ compilers or HP-UX linker. The cadvise command is used as a wrapper around the compile and link command-line options (hereafter referred to as build line). The cadvise command and options are prefixed to the build line as command line arguments.
For example
The following command lines show how to invoke cadvise: Regular command line: $ cc -c abc.c def.c Cadvise command line: $ cadvise -pdb mypdb +wlint cc -c abc.c def.c
$ cadvise -pdb mypdb +wlint cc -c abc.c def.c $ cadvise -pdb mypdb +wlint ld -r abc.o def.o -o abcdef.o
The cadvise command first executes the user's regular build line, and then analyzes the source code. Cadvise also analyzes the build line and automatically determines the include paths, defines, and language dialect needed for the source code analysis. The -nobuild option allows you to skip the regular build process, and perform only the source code analysis.
The result of the cadvise analysis can be stored in a program database using the -pdb option. In this case, the PDB also stores the summary information used for cross-file analysis. For more information on PDB, see Using the Program Database (PDB) (page 19).

2.5 Integrating Cadvise with the makefiles and build process

Cadvise can be easily integrated with the makefiles and the build scripts. If a makefile variable is used to define the C and C++ compilers, you can redefine it to include the cadvise invocation.
Example 1 Updating the makefile to integrate cadvise
See the following makefile content:
CADVISE_OPTS= -pdb mypdb +wlint CADVISE= /opt/cadvise/bin/cadvise CC= $(CADVISE) $(CADVISE_OPTS) /opt/ansic/bin/cc CXX= $(CADVISE) $(CADVISE_OPTS) /opt/aCC/bin/aCC
You may also define a wrapper script instead of the standard compiler commands. For example, see the following sample wrapper script:
12 Using Cadvise
Example 2 Sample wrapper script
$ cat cadvise_cc #!/bin/sh # # wrapper script to invoke cadvise # exec /opt/cadvise/bin/cadvise -pdb mypdb +wlint /opt/ansic/bin/cc "$@"
Now cadvise_cc can be used instead of cc in the build line to invoke cadvise analysis in addition to the compilation process.
NOTE: You need not create separate dependency rules for cadvise in the makefiles. Cadvise
must be invoked only when the existing dependency rules in the makefile lead to a compile.
The addition of cadvise analysis to the build process increases the total build time. You can either invoke cadvise automatically whenever compiled, or launch cadvise as a separate build process by invoking it explicitly. For large projects where a lot of cross-file analysis is required, it is better to separate the analysis process. You can use the -crossfile option to manage the cross-file analysis.

2.6 Enabling different categories of diagnostic messages

By default, a limited number of diagnostic messages are enabled in cadvise. Additionally, the following options can be used to enable various types of diagnostic messages.
+w
“+wlint” (page 45)
“+w64bit ” (page 51)
” (page 54)
Enables all the warnings about potentially questionable constructs in the compiler.
Enables all the compile time checks.+wall
Detects code fragments which are endian dependent.“+wendian” (page 51)
Provides compile-time diagnostics which detect potential errors in the source code.
Detects multi-threaded programming issues.“+wlock” (page 53)
Enables compile time diagnostic messages for potential security vulnerabilities.“+wsecurity[=1|2|3|4]” (page 52)
Enables warnings that help detection of potential problems in converting 32-bit applications to 64-bit.
Generates performance advisory diagnostics.“+wperfadvice[=1|2|3|4]
The best method is to use +wall to enable all possible diagnostic messages. Then, use the cadvise report -pdb <pdbname> -summary command to see a quick summary of the various diagnostic messages generated by cadvise, sorted by severity. For more information, see Generating
Reports (page 27).

2.7 Generating code complexity metrics

Cadvise can generate code complexity metrics to gauge the complexity of the code being developed or migrated. The +metrics option generates program complexity metrics.
Syntax:
$cadvise +metrics[=ict][:out=pdb]
OR
$cadvise +metrics[=ict][:out=[+]<filename>]
Following command shows the examples for generating code complexity metrics.
2.6 Enabling different categories of diagnostic messages 13
Example 3 Generating code complexity metrics
To store the code complexity metrics in the PDB with Indirect Call Targets, use the following command.
$cadvise +metrics=ict -pdb test.pdb aCC -c example.c
To get the metrics in the my.metrics file, use the following command.
$cadvise +metrics :out=my.metrics aCC -c example.c
To store the metrics in the my.metrics file without Indirect Call Targets, use the following command.
$cadvise +metrics :out=pdb -pdb test.pdb aCC -c example.c
The program complexity metrics are stored in a specified output location. The output location can either be specified as the pdb (out=pdb) or a file <filename>(out=<filename>). Inserting a + before the <filename> appends the metrics to the file <filename>. If the output location is not specified, then these metrics are written either to a PDB, if a PDB is present, or to the file <objfile>.metrics.
Cadvise emits the following metrics for determining program complexity:
For a source file
Number of header files included◦ ◦ Total number of lines in the source file Number of comment lines Number of blank lines Number of lines of code Number of mixed lines (lines have both code and comments) Number of global variables Number of static variables Total number of functions defined Number of externally visible functions defined Number of global Thread Local Storage (TLS) Variables Number of static Thread Local Storage (TLS) Variables Number of global mutexes Number of static mutexes Program complexity metrics for each of the functions
For a function
Function Signature◦ ◦ Total number of lines Number of comment lines Number of blank lines Number of lines of code Number of mixed lines Number of macros used Number of local variables defined Number of static variables defined
14 Using Cadvise
Number of if statements Number of return statements Number of loop nests Nesting level of each loop nest Number of indirect calls Number of direct calls Targets of direct calls Cyclomatic complexity Cyclomatic complexity without switch Cyclomatic complexity without exception handling Cyclomatic complexity without switch and exception handling Number of Thread Local Storage (TLS) variables Number of mutexes Number of lock calls Number of unlock calls
For each indirect call site, cadvise emits the list of possible call targets.
Cyclomatic Complexity
Cyclomatic complexity metric, developed by Thomas McCabe in 1976 ,measures the number of linearly-independent paths through a program module. It is an indicator for understandability and testability of a module. A lower value indicates more understandable and testable code. The +metrics option emits cyclomatic complexity by default.
Indirect Call Targets
This refers to the list of functions that can be called at an indirect call site. Calculation of this metric leads to an increase in analysis time and so the +metrics option does not emit Indirect Call Targets by default. You need to specify ict as a suboption to the +metrics option for emission of indirect call targets. This causes emission of Indirect Call Targets in addition to all other default metrics.
The following example shows the code complexity metrics.
2.7 Generating code complexity metrics 15
Example 4 Code complexity metrics
$ cat /tmp/example.c
#include <stdio.h> #include <pthread.h>
#define INDEX 500
pthread_mutex_t mutex;
int mata[INDEX][INDEX], matb[INDEX][INDEX], matres[INDEX][INDEX] ; void print_output(); void matrix_multiply() { int i, j, k ; /* Matrix-Matrix multiply */ for (i = 0 ; i < INDEX ; i++) { for (k = 0 ; k < INDEX ; k++) { for (j = 0 ; j < INDEX ; j++) { matres[i][j] = matres[i][j] + mata[i][k] * matb[k][j] ; } } } print_output(); /* print the result of multiplication */ return; }
$ cadvise +metrics aCC -c /tmp/example.c
$ cat example.metrics
======================================================================= Begin program complexity data for /tmp/example.c =======================================================================
File level program complexity data :
------------------------------------
Include Files: 2 Total Lines: 23 Blank Lines: 3 Comment Lines: 1 Lines Of Code: 19 Mixed Lines: 1 No. of Globals: 4 No. of Statics: 0 No. of Functions: 1 No. of ExternFunctions: 1 No. of Global Thread Local Variables: 0 No. of Static Thread Local Variables: 0 No. of Global Mutexes: 1 No. of Static Mutexes: 0
Function level program complexity data :
----------------------------------------
Begin Function: matrix_multiply Signature: void matrix_multiply() Total Lines: 15 Blank Lines: 1 Comment Lines: 1 Lines of Code: 13 Mixed Lines: 1
16 Using Cadvise
No. of Macros Used: 3 No. of Locals: 3 No. of Statics: 0 No. of Ifs: 0 No. of Returns: 1 No. of Loops: 1 Loop Nesting Levels: 3 No. of Indirect Calls: 0 No. of Direct Calls: 1 Functions called: print_output() Cyclomatic Complexity: 4 Cyclomatic complexity without switches: 4 Cyclomatic complexity without eh: 4 Cyclomatic complexity without switches and eh: 4 No. of Thread Local Variables: 0 No. of Mutexes: 0 No. of Lock Calls: 0 No. of Unlock Calls: 0 End Function: matrix_multiply ================================================================== End program complexity data for /tmp/example.c ==================================================================
NOTE: The +metrics option can be used with the cadvise reporting option for reporting program
complexity metrics from the PDB.

2.8 Detecting violation of pre-defined or user-defined coding guidelines

The coding guidelines checker diagnoses violations to the coding guidelines and emits appropriate diagnostic messages.
Syntax:
+wcodeguide[=<rules-library>]
Where: rules-library denotes the library that defines the coding guideline rules. You can modify the default set of rules or write your own set of rules to enforce coding guidelines.
Cadvise has the appropriate API header files and a set of sample files along with the corresponding makefile to rebuild the rules library.
Table 2 lists the source structure provided for (re)building the rules library.
2.8 Detecting violation of pre-defined or user-defined coding guidelines 17
Table 2 Source structure in the rules library
include/
lib/
src/
HPCodeGuideConstructs.h
Contains the APIs required for (re)writing the rules to enforce coding guidelines.
HPCodeGuideDiagnosticTags.h
Contains the various diagnostic tags that you can use to emit the diagnostics from the rules library.
libcodeguide.a
This is provided to fill in the implementation stubs for recompilation of the rules' library, and must be linked in while compiling the rules' library.
librules.s[lo]
This is the default rules' library that is available with cadvise.
HPCodeGuideRules.C
The file where all rules are implemented. You can modify this file to incorporate more rules and/or modify the existing ones.
HPCodeGuideRulesDriver.C
The driver from where the rules are invoked on the various program constructs.
Makefile
The default makefile for rebuilding the rules' library from the above sources.
The sample rules towards naming convention that are available with the current release are as follows:
1. Functions that returns a bool must start with is.
2. Names of abstract classes should begin with Interface.
3. Class names should start with a capital letter.
4. Names of global variables should start with a capital letter.
5. Names of local variables should start with a small letter.
An example of writing a rule to enforce the naming convention of private data members being suffixed with an '_' is as follows:
Example 5 Writing a rule to enforce naming convention
void Field::checkNamingConventions() { //Private data members of class should end with "_" if(name() && isPrivate()) { char ch = *name() + strlen(name()); if(ch != '_') warning("Private data member \"%s\" not suffixed with \"_\"", 2000053, name()); } }
NOTE: Cadvise reports do not currently have support for Coding Guideline diagnostics. Use the
-tee option to view these messages.
18 Using Cadvise
Loading...
+ 41 hidden pages