NAME

Devel::TypeCheck - Identify type-unsafe usage in Perl programs

VERSION

Version 0.02

SYNOPSIS

This file exists as a placeholder for the documentation. To use, invoke the B::TypeCheck module as one normally would with any other compiler back-end module:

perl -MO=TypeCheck[,-verbose][,-main][,I<subroutine> ...] I<SCRIPTNAME>

OPTIONS

-verbose

Print out the relevant parts of the opcode tree along with their inferred types. This can be useful for identifying where a type-inconsistant usage is in your program, and for debugging TypeCheck itself.

-main

Type check the main body of the Perl program in question.

subroutine

Type check a specific subroutine. In this release, TypeCheck does not do generalized interprocedural analysis. However, it does keep track of types for global variables.

EXAMPLES

Here is an example program that treats $foo in a type-consistent manner:

# pass
if (int(rand(2)) % 2) {
    $foo = 1;
} else {
    $foo = 2;
}

When we run the TypeChecker against this program, we get the following output:

Type checking CVs:
  main::MAIN
  Pad Table Types:
  Name                Type
  ---------------------------------------- 

  Result type of main::MAIN is undefined
  Return type of main::MAIN is undefined

Global Symbol Table Types:
Name                Type
------------------------------------------------------------------------------
foo                 MH:...,MKN<IV>
Total opcodes processed: 24
2.pl syntax OK

The indented stanza indicates that there are no named local variables in MAIN.

The stanza at the bottom shows that we have a global variable named foo of the glob (MH:...) type that contains an integer (MKN<IV>) in its scalar value element.

Here is another that does not:

# fail
if (int(rand(2)) % 2) {
    $foo = 1;
} else {
    $foo = \1;
}

We get the following when we run TypeChecker against the project:

Type checking CVs:
  main::MAIN
Could not unify MKPMKN<IV> and C<< MKN<IV> >> at line 5, file 3.pl
CHECK failed--call queue aborted.

This means that the type inference algorithm was not able to unify a reference to an integer type (MKPMKN<IV>) with an integer type (MKN<IV>). To get a better idea about how this works, we will look at the verbose output (with lines numbered and extraneous lines removed for clarity):

24	                S:leave {
25	                    S:enter {
26	                    } = void
27	                    S:nextstate {
28	                      line 3, file 3.pl
29	                    } = void
30	                    S:sassign {
31	                        S:const {
32	                        } = MKN<IV>
33	                        S:null {
34	                            S:gvsv {
35	                            } = MKf
36	                        } = MKf
37	                      unify(MKN<IV>, MKf) = MKN<IV>
38	                    } = MKN<IV>
39	                } = void
40	                S:leave {
41	                    S:enter {
42	                    } = void
43	                    S:nextstate {
44	                      line 5, file 3.pl
45	                    } = void
46	                    S:sassign {
47	                        S:const {
48	                        } = MKPMKN<IV>
49	                        S:null {
50	                            S:gvsv {
51	                            } = MKN<IV>
52	                        } = MKN<IV>
53	                      unify(MKPMKN<IV>, MKN<IV>) = FAIL
54	Could not unify MKPMKN<IV> and MKN<IV> at line 5, file 3.pl
55	CHECK failed--call queue aborted.
56	Type checking CVs:
57	  main::MAIN

Lines 30-38 represent the assignment that constitutes the first branch of the if statement. Here, an integer constant (MKN<IV>, lines 31-32) is assigned to the variable represented by the gvsv operator (lines 34-35). The variable is brand new, so it is instantiated with a brand new unspecified scalar value type (MKf). This is unified with the constant (line 37), binding the type variable "f" with the concrete type <IV>.

Lines 46-53 represent the assignment that consitutes the second branch of the if statement. Like the last assignment, we generate a type for our constant. Here, the type is a reference to an integer (MKPMKN<IV>, lines 47-48). Since we have already inferred an integer type for the $foo variable, that is what we get when we access it with the gvsv operator (MKN<IV>, lines 50-51). When we try to assign the constant to the variable, we get a failure in the unification since the types do not match and there is no free type variable to unify type components with.

REFERENCES

The author has written a paper explaining the need, operation, results, and future direction for this project. It is available at the following URL:

http://www.umiacs.umd.edu/~bargle/project2.pdf

This is suggested reading for this release. In future releases, we hope to have a proper manual.

AUTHOR

Gary Jackson, <bargle at umiacs.umd.edu>

BUGS

This version is specific to Perl 5.8.1. It may work with other versions that have the same opcode list and structure, but this is entirely untested. It definitely will not work if those parameters change.

Please report any bugs or feature requests to bug-devel-typecheck at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Devel-TypeCheck. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

COPYRIGHT & LICENSE

Copyright 2005 Gary Jackson, all rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.