0% found this document useful (0 votes)
983 views80 pages

CSC201 Sec 1 Proj 2 Team 6

The SEI CERT C and Java Coding Standards provide guidelines for secure coding practices to enhance safety, reliability, and security in software development. The document outlines specific rules and recommendations for C programming, including examples of noncompliant and compliant code, as well as risk assessments for various coding practices. It emphasizes the importance of adhering to these standards to prevent vulnerabilities and undefined behaviors in software systems.

Uploaded by

varuncv2001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
983 views80 pages

CSC201 Sec 1 Proj 2 Team 6

The SEI CERT C and Java Coding Standards provide guidelines for secure coding practices to enhance safety, reliability, and security in software development. The document outlines specific rules and recommendations for C programming, including examples of noncompliant and compliant code, as well as risk assessments for various coding practices. It emphasizes the importance of adhering to these standards to prevent vulnerabilities and undefined behaviors in software systems.

Uploaded by

varuncv2001
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 80

CSC 201

CSC – 201

SEI CERT C Coding Standard


SEI CERT Oracle Java Coding Standard

Team Members:
Sasi Kiran Kanduri
Ashish Tharanath Kotian
Rajasekhar Reddy Kolagotla
Chanakya Rudhra Baluguri
Introduction

• This standard provides rules for secure coding in the C/Java programming
languages. The goal of these rules and recommendations is to develop safe,
reliable, and secure systems, for example by eliminating undefined behaviors that
can lead to undefined program behaviors and exploitable vulnerabilities.

• Coding standards encourage programmers to follow a uniform set of rules


determined by the requirements of the project and organization rather than by the
programmers’ individual preferences. This helps build and maintain secure and
strong codebases.
Audience
• Primarily designed for developers of C/Java developers.
• These standards are of particular interest to developers who are building
high-quality systems that are reliable, robust, and resistant to attack.

Rules and Recommendations


Rules and Recommendations are collectively referred to as guidelines.

Rules Recommendations
● Violation of the guideline -> may ● Suggestions for improving code
adversely affect the safety, quality
reliability, or security of a system. ● Application of a guideline is likely to
Example: Security flaw -> exploitable improve the safety, reliability, or
Vulnerability security of software systems
● guideline does not rely on source code ● One or more of the requirements
annotations or assumptions necessary for a guideline to be
considered a rule cannot be met
Rules and Recommendations
Noncompliant Code Examples and Compliant Solutions
• Illustrate code that violates the guideline under discussion.
• Noncompliant code examples are typically followed by compliant solutions.
• Compliant solutions should comply with all of the secure coding rules but may on
occasion fail to comply with a recommendation.

Exceptions
• Exceptions can be specified for any rules or recommendations.
• Coding practices that specify one or more exceptions are identified by the
label exceptions.

Identifiers
Each rule and recommendation are given a unique identifier
o A three-letter mnemonic representing the section of the standard
o A two-digit numeric value in the range of 00 to 99
o The letter "J" indicates that this is a Java language guideline
Priority and Levels
Each rule has an assigned priority. Priorities are assigned using a metric based on
Failure Mode, Effects, and Criticality Analysis.
Severity—How serious are the consequences of the rule being ignored?

Likelihood—How likely is it that a flaw introduced by violating the rule can lead to an
exploitable vulnerability?
Rule: Priority and Levels
Remediation Cost—How expensive is it to comply with the rule?

Priority Levels
Rules For C

INT Rule04:
•INT33-C. Ensure that division and remainder operations do not result in divide-by-zero
errors

•INT34-C. Do not shift an expression by a negative number of bits or by greater


than or equal to the number of bits that exist in the operand

•INT35-C. Use correct integer precisions

•INT36-C. Converting a pointer to integer or integer to pointer


INT 33-C. The value of the second operand of
the / or % operator is zero.

● Division: The result of the / operator is the quotient from the division of the
first arithmetic operand by the second arithmetic operand. Division operations
are susceptible to divide-by-zero errors.

● Remainder: The remainder operator provides the remainder when two


operands of integer type are divided.

● The second operator should not be zero to prevent such errors.


Noncompliant Code Example:
● Ensures overflow prevention but does not prevent division-by-zero errors on
remainder operations.

● s_b can be passed as 0


Compliant Code Example:
This code checks for the value of the second operand before performing the division.

Risk Assessment:
A divide-by-zero error can result in abnormal program termination and denial
of service.
INT 34-C.
Do not shift an expression by a negative number of bits or by greater
than or equal to the number of bits that exist in the operand
.

● Do not shift an expression by a negative number of bits or by a number greater than


or equal to the precision of the promoted left operand.
● The precision of an integer type is the number of bits it uses to represent values
● Bitwise shifts include left/right operations of the form
○ shift-expression << additive-expression
○ shift-expression >> additive-expression
● For unsigned width and precision are the same
● For signed , width is one or more greater.
● Shifting by a number greater than the precision of the left operand will result in a
bug(logic error)
● In general shifts should be performed only on unsigned operands
Non-Compliant Code:

Does not Ensure that the right operand is not greater than the precision of the left
operand.

Right Shift :
Compliant Code Example:
The following compliant solution uses the popcount() method to calculate the
precision and makes sure that right operand is less that it.
Non-Compliant Code (signed Type):

This noncompliant code example fails to ensure that left and right operands have
nonnegative values and that the right operand is less than the precision of the
promoted left operand. This example does check for signed integer overflow.
In addition to the check for overflow, this compliant solution ensures that both the
left and right operands have nonnegative values and that the right operand is less
than the precision of the promoted left operand
Risk Assessment:
Although shifting a negative number of bits or shifting a number of bits greater than
or equal to the width of the promoted left operand is undefined behavior in C, the
risk is generally low because processors frequently reduce the shift amount modulo
the width of the type.
INT 35-C. Use Correct Integer Precisions.
● Integer types in C have precision.
● Precision is the number of bits used to represent the integer value.
● It can be retrieved for any object or type.
● Padding Bits: extra bits of 0 added to the higher end of integers to adhere to the
platform(computer architecture , 32/64).
● Programmers should use correct precision to avoid logic errors. *

Non-Compliant Code:
● This code is a function to returns 2 raised to the power of the argument. 2 exp.
● This function ensures the compliance of INT 34-C by checking that argument is less that number
of bits used to store the value.
● If this function runs on a platform where unsigned int is 64 bits but uses only 48 bits to represent
the value, this may result in undefined behavior.
Compliant Code:
● This function counts the number of bits of any unsigned integer.
● Can be used to calculate precision. We will need this function to revise a
compliant solution for INT 35-C.
● Using the popcount() function, we can define a revised pow2 function previously
discussed.
● The revised version of the pow2() function uses the PRECISION() macro to
determine the precision of the unsigned type:

● Some platforms, such as the Cray Linux Environment , provides a _popcnt


instruction that can be used instead of popcount() function.
Risk Assessment:

Invalid precision can lead to errors in shift operations and cause undefined behaviors.
INT 36-C. Converting a pointer to integer or an integer
to pointer.
● Do not convert a pointer type to an integer type if the result cannot be
represented in the integer type.

● A pointer stores the address location and returns the value in that location.

● Converting a pointer to an integer may not always be right as there may be


software implementations with pointers have more bit width than integer type.

● Do not convert an integer type to a pointer type if the resulting pointer is


incorrectly aligned, does not point to an entity of the referenced type.

● Conversions between integers and pointers can have undesired consequences


depending on the implementation.
Non-Compliant Code:

This code will be wrong on an implementation of 64-bit ptr and 32-bit unsigned int.
A 64-bit ptr cannot be represented in a 32-bit integer.

Implementation:

Particular set of software, running in a particular translation environment under


particular control options, that performs translation of programs for, and supports
execution of functions in, a particular execution environment.
Compliant Code:

● C provides types intprt_t and uintptr_t to convert a valid pointer to integer and
back again to pointer with no change in value.

● Converting directly from a char * pointer to a uintptr_t, as in this compliant


solution, is allowed on implementations that support the uintptr_t type.
Noncompliant Code Example(integer to pointer):

Sometimes, its necessary to access memory at a specific location, requiring a literal


integer to pointer conversion.

Now, this code is implementation-defined. It might work on a certain implementation


and might not on another. (might not point to a right type).
There is no general way to make this code Compliant as per this ISO C.
Exceptions:

● INT 36-C-EXC1: An integer to pointer is always safe when the integer is 0 as it will
result in a null pointer.
● In general, any pointer to void can be changed to intptr_t or uintptr_t and back
with no change in the value.

● Here, void generally does not have type so it can be changed back and forth.
Risk Assessment:

Converting from pointer to integer or integer to pointer may result in creation of


unexpected pointers to invalid memory locations.
Recommendations For C

Rec. 04. Integers (INT):


● INT05-C. Do not use input functions to convert character data if they cannot
handle all possible inputs

● INT07-C. Use only explicitly signed or unsigned char type for numeric values

● INT08-C. Verify that all integer values are in range

● INT09-C. Ensure enumeration constants map to unique values


INT05-C. Do not use input functions to convert character
data if they cannot handle all possible inputs
● Do not use formatted input functions that take input characters and convert them to
integers if the functions cannot handle all possible inputs.
● Formatted input functions such as scanf(), fscanf(), vscanf(), and vfscanf() can be
used to read string data from the stdin input stream. These functions work fine for
valid integer values but lack robust error handling for invalid values.

● The reason for discouraging the use of formatted input stems from the fact that
there is no way to detect if overflow or underflow has occurred and it would simply
return a random value instead of the input given.
Noncompliant Code: Compliant Solution (Linux):

/* If a value greater than LONG_MAX is


given as an input it would return a random
value.*/
This noncompliant code example uses the This compliant example uses the Linux scanf()
scanf() function to read a string from stdin implementation built-in error handling to
validate input.On Linux platforms, scanf() sets
and convert it to a long. Do not use scanf()
errno to ERANGE if the result of integer
to parse integers or floating-point numbers conversion cannot be represented within the
from input strings because the input could size specified by the format string.
contain numbers not representable by the
argument type. Note: This solution is platform dependent, so it
should be used only where portability is not a
concern.
Compliant Solution:
This compliant example uses fgets() to input a string and strtol() to convert the string to
an integer. Error checking is provided to make sure the value is a valid integer in the range
of long.

// Here we make use of fgets to take the


input

//strtol is used to covert input string and assign it to


num_long
Risk Assessment:

Although it is relatively rare for a violation of this recommendation to result in a security


vulnerability, it can easily result in lost or misinterpreted data.
INT07-C. Use only explicitly signed or unsigned char type
for numeric values
• There are three character types such as char, signed char, and unsigned char.
Compilers have the latitude to define char to have the same range, representation,
and behavior as either signed char or unsigned char
• Irrespective of the choice made, char is a separate type from the other two and is
not compatible with either.

• Use only signed char and unsigned char types for the storage and use of numeric
values because it is the only portable way to guarantee the signedness of the
character types.
Noncompliant Code : Compliant Solution:

/*char c = 200 will have value -56 */ /* Output = 5 */


/* Output = -17
In this noncompliant code example, In this compliant solution, the variable c is
the char-type variable c may be
signed or unsigned. Assuming 8-bit, declared as unsigned char. The
two's complement character types, subsequent division operation is now
this code may print out either i/c = 5 independent of the signedness of char
(unsigned) or i/c = -17 (signed) and consequently has a predictable
result.
It is much more difficult to reason
about the correctness of a program
without knowing if these integers
are signed or unsigned.
Exceptions:

INT07-C-EX1: void FIO34-C. Use int to capture the return value of character IO
functions that might be used to check for end of file mentions that certain character
IO functions return a value of type int. Despite being returned in an arithmetic type, the
value is not actually numeric in nature, so it is acceptable to later store the result into a
variable of type char.

Risk Assessment:
This is a subtle error that results in a disturbingly broad range of potentially severe
vulnerabilities. At the very least, this error can lead to unexpected numerical results on
different platforms. Unexpected arithmetic values when applied to arrays or pointers can
yield buffer overflows or other invalid memory access.
INT08-C. Verify that all integer values are in range
● Integer operations must result in an integer value within the range of the integer type
● The range is more restrictive depending on the use of the integer value.
Ex: Index of an array.

● Integer overflow is undefined behavior, so a compiled program can do anything,


including going off to play the Game of Life or a compiler may perform optimizations
that assume an overflow will never occur, which can easily yield unexpected results.
● Verifying the in-range operations are often preferable to treating out-of-range values
as an error condition because the handling of these errors has been repeatedly shown
to cause denial-of-service problems in actual applications

● A program that detects an integer overflow to be imminent may do one of two things:
(1) Signal some sort of error condition: This can be handled by an error condition
complaining about a bad input and request for a new input.
(2) Produce an integer result that is within the range of representable integers on that
system and proceed with the computation thereby avoiding denial of service.
To produce integer results we can make use of these 3 techniques:
1) Saturation Semantics
2) Modwrap Semantics
3) Restricted Range Usage

Saturation Semantics:
The value returned to the user is set out in the following table:

/* Here, result is the value obtained from


integer operation */
Modwrap Semantics:

In modwrap semantics (also called modulo arithmetic), integer values "wrap round." That
is, adding 1 to MAX produces MIN. This is a defined behavior of both signed int and
unsigned int. But it is more sensible to use saturation semantics instead of modwrap.

Ex: In the computation of a size (using unsigned integers), it is often better for the size to
stay at the maximum value in the event of overflow rather than to suddenly become a very
small value.

Restricted Range Usage:

Another technique for avoiding integer overflow is to use only half the range of signed
integers. For example, when using an int, use only the range [INT_MIN/2, INT_MAX/2].
This practice has been a trick of the trade in Fortran for some time, and now that
optimizing C compilers are more sophisticated, it can be valuable in C.

Ex: Consider subtraction. If the user types the expression a - b, where both a and b are in
the range [INT_MIN/2, INT_MAX/2], the result will be in the range (INT_MIN, INT_MAX]
for a typical two's complement machine.
NoncompliantCode: CompliantSolution:

In this noncompliant example, i + 1 will Using a long instead of an int it is


overflow on a 16-bit machine. The C guaranteed to accommodate the computed
Standard allows signed integers to
value
overflow and produce incorrect
results. Compilers can take advantage
of this to produce faster code by
assuming an overflow will not occur.
As a result, the if statement that is
intended to catch an overflow might
be optimized away.
Risk Assessment:

Out-of-range integer values can result in reading from or writing to arbitrary memory
locations and the execution of arbitrary code.
INT09-C. Ensure enumeration constants map to unique values.

• An enumerated type is a user-defined type that is used to assign names to


integral contents because names are easier to handle in a program.
• It is a constant integer expression whose value is representable as an int.

• C language allows multiple enumerators of the same type to have the same
value, it is a common expectation that all enumerators of the same type have
distinct values.
• Defining two or more enumerators of the same type to have the same value
can lead to some nonobvious errors.
Noncompliant Code:
• In the Noncompliant code, two enumerators of type Color are assigned explicit values.

/* Here: red=4, orange=5, yellow= 6, green=7, blue=8, indigo=6, violet=7(all unassigned


names will get value as value of previous name+1) */

• It may not be obvious to the programmer that yellow and indigo have been declared
to be identical values (6), as are green and violet (7).

• The following code violates this semantic constraint and is required to be diagnosed by
a confirming compiler.
Compliant Solution:
To prevent the error discussed of the noncompliant code example, enumeration type
declarations must take one of the following forms:

• Provide no explicit integer assignments, as in this example:

• Assign a value to the first member only (the rest are then sequential), as in this example:

• Assign a value to all members so any equivalence is explicit, as in this example:

enum Color { red=4, orange=5, yellow=6, green=7, blue=8, indigo=6, violet=7 };

Of these three options, providing no explicit integer assignments is the preferred approach
unless the first enumerator must have a nonzero value.

Note: It is advisable to provide a comment explaining why multiple enumeration type


members are being assigned the same value.
Exceptions:

INT09-C-EX1: In cases where defining an enumeration with two or more enumerators with
the same value is intended, the constant expression used to define the value of the
duplicate enumerator should reference the enumerator rather than the original
enumerator's value.

Risk Assessment:

Failing to ensure that constants within an enumeration have unique values can result in
unexpected results.
Rules For Java
NUM Rule03:

• NUM09-J. Do not use floating-point variables as loop counters

• NUM10-J. Do not construct BigDecimal objects from floating-point literals

• NUM11-J. Do not compare or inspect the string representation of floating-point


values

• NUM12-J. Ensure conversions of numeric types to narrower types do not result in


lost or misinterpreted data

• NUM13-J. Avoid loss of precision when converting primitive integers to floating-


point

• NUM14-J. Use shift operators correctly


Rule: NUM09-J. Do not use floating-point variables
as loop counters

• Floating-point variables must not be used as loop counters because the processing
takes a lot of time and also if the processor doesn't have floating-point hardware,
it will take way more time to do a simple increment.

• For the purpose of this rule, a loop counter is an induction variable that is used as
an operand of a comparison expression that is used as the controlling expression
of a do, while or for loop.

• An induction variable is a variable that gets increased or decreased by a fixed


amount on every iteration of a loop. Furthermore, the change to the variable must
occur directly in the loop body (rather than inside a function executed within the
loop.)
Noncompliant Code Example:

• Noncompliant code example uses a floating-point


variable as a loop counter.
• The decimal number 0.1 cannot be represented either as a float or as a double.
• Because 0.1f is rounded to the nearest value that can be represented in the value set of
the float type, for each iteration the value added to x will be greater than 0.1.
Consequently, the loop executes only nine times and typically fails to produce the
expected output.

Compliant Code Example:

• This compliant code solution uses an


integer loop counter from which the desired
floating-point value is derived:

Risk Assessment:
Rule: NUM10-J. Do not construct BigDecimal objects
from floating-point literals
• Literal decimal floating-point numbers cannot always be precisely
represented as an floating-point value.
• Consequently, the BigDecimal (double val) constructor must not be passed a
floating-point literal as an argument, when doing so results in an
unacceptable loss of precision.

Non - Compliant Code:

• This noncompliant code example passes a double value


to the BigDecimal constructor. Because the decimal literal 0.1 cannot be
precisely represented by a double, precision of the BigDecimal is affected.
Compliant Code Example:

This compliant solution passes the decimal literal as a String so that


the BigDecimal(String val) constructor is invoked and the precision is preserved:

Risk Assessment:

Using the BigDecimal(double val) constructor with decimal floating-point literals


can lead to loss of precision.
Rule: NUM11-J. Do not compare or inspect the string
representation of floating-point values
• String representations of floating-point numbers must not be compared or inspected.

Non-Compliant Code Example (String Comparison):

• This noncompliant code example compares the string


representations of two floating-point values:
• The comparison unexpectedly fails because s contains
the string "0.0010", which is not equal to "0.001".

Non-Compliant Code Example (Regex):

• This noncompliant code example attempts


to mitigate the extra trailing zero by using
a regular expression on the string
before comparing it:
Non-Compliant Code Example (Regex): (Cont..)

• Although the comparison succeeds on the preceding code, it fails on the


following similar code, which uses 1/10000.0 instead of 1/1000.0.
• The string produced is not 0.00010
but rather 1.0E-4.

Compliant Solution (String Comparison):


This compliant solution uses the BigDecimal class to avoid precision loss. It
then performs a numeric comparison, which passes as expected.

Risk Assessment:
Comparing or inspecting the string representation of floating-point values may
have unexpected results.
Rule: NUM12-J. Ensure conversions of numeric types to narrower
types do not result in lost or misinterpreted data
• Conversions of numeric types to narrower types can result in lost or misinterpreted
data if the value of the wider type is outside the range of values of the narrower type.
• Consequently, all narrowing conversions must be guaranteed safe by range-checking
the value before conversion.
• Java provides 22 possible narrowing primitive conversions.
• short to byte or char
• char to byte or short
• int to byte, short, or char
• long to byte, short, char, or int
• float to byte, short, char, int, or long
• double to byte, short, char, int, long, or float
• Narrowing primitive conversions are allowed in cases where the value of the wider
type is within the range of the narrower type.
Non-Compliant Code Example (Integer Narrowing):

• In this noncompliant code example, a value of type int is converted


to a value of type byte without range checking:

• The resulting value may be unexpected


because the initial value (128) is
outside of the range of the resulting type.

Compliant Code Example (Integer Narrowing):

• This compliant solution validates that the


value stored in the wider integer type is
within the range of the narrower type
before converting to the narrower type.
• It throws an ArithmeticException if the
value is out of range.
• When integers are cast to narrower data types, the magnitude of the numeric
value and the corresponding sign can be affected. Consequently, data can be lost
or misinterpreted.

Risk Assessment:

• Casting a numeric value to a narrower type can result in information loss related
to the sign and magnitude of the numeric value. As a result, data can be
misrepresented or interpreted incorrectly.
Rule: NUM13-J. Avoid loss of precision when
converting primitive integers to floating-point
• The following 19 specific conversions on primitive types are called the widening
primitive conversions:
• byte to short, int, long, float, or double
• short to int, long, float, or double
• char to int, long, float, or double
• int to long, float, or double
• long to float or double
• float to double

• Conversions from integral types smaller than int to a floating-point type and
conversions from int to double can never result in a loss of precision. Consequently,
programs must ensure that conversions from an int or long to a floating-point type or
from long to double do not result in a loss of required precision.
Non-Compliant Code Example:

• In this noncompliant code example, two identical large integer literals are passed as arguments to
the subFloatFromInt() method. The second argument is coerced to float, cast back to int, and
subtracted from a value of type int. The result is returned as a value of type int.
• This method could have unexpected results because of the loss of precision. The exponent allows
type float to represent a larger range than that of type int. However, the 23-bit mantissa means
that float supports exact representation only of integers whose representation fits within 23
bits; float supports only approximate representation of integers outside that range.

• Note that conversions from long to either float or


double can lead to similar loss of precision.

Compliant Code Example (ArithmeticException):

This compliant solution range checks


the argument of the integer argument
(op1) to ensure it can be represented as a
value of type float without a loss of precision:
Compliant Code Example (Wider Type):
• This compliant solution accepts an argument of type double instead of an argument of type float.
In FP-strict mode, values of type double have 52 mantissa bits, a sign bit, and an 11-bit exponent.
Integer values of type int and narrower can be converted to double without a loss of precision.
• Note that this compliant solution cannot be used when the primitive integers are of
type long because Java lacks a primitive floating-point type whose mantissa can represent the full
range of a long.

Exceptions:
NUM13-J-EX0: Conversion from integral types to floating-point types without a range check is
permitted when suitable numerical analysis demonstrates that the loss of the least significant bits of
precision is acceptable.
Rule: NUM14-J. Use shift operators correctly
• The shift operators in Java have the following properties,
• “>>” right shift is an arithmetic shift; “>>>” right shift is a logical shift.
• types boolean, float, and double can’t use the bit-shifting operators.
• When the value to be shifted is of type int, only the five lowest-order bits of
the right-hand operand are used as the shift distance.
• When the value to be shifted (left operand) is type long, only the last 6 bits
of the right-hand operand are used to perform the shift.
• The value to the right of a shift operation must be within the appropriate range
for the type of the numeric value to the left of the shift operation.
Rule: NUM14-J. Use shift operators correctly
• Arithmetic vs. Logical Shift:

• The JLS, defines the behavior of the arithmetic shift operator as follows:
• The value of n>>s is n right-shifted s bit positions with sign-extension. The resulting
value is floor(n / 2s). For nonnegative values of n, this is equivalent to truncating integer
division, as computed by the integer division operator /, by two to the power s.
• The JLS also defines the behavior of the logical shift operator:
• The value of n >>> s is n right-shifted s bit positions with zero-extension, where:
• If n is positive, then the result is the same as that of n >> s.
• If n is negative and the type of the left-hand operand is int, then the result is
equal to that of the expression (n >> s) + (2 << ~s).
• If n is negative and the type of the left-hand operand is long, then the result is
equal to that of the expression (n >> s) + (2L << ~s).
• Never use the arithmetic shift operator when the logical shift operator is required.
Noncompliant Code Example (Arithmetic vs. Logical):

• In this noncompliant code example, method


countOneBits loops forever on negative
inputs because the >> operator performs an
arithmetic shift rather than a logical shift:

Compliant Code Example (Arithmetic vs. Logical):

• This compliant solution uses the logical shift


operator >>>, which clears vacated bits
(that is, shifts in zero-bits on the left):
Noncompliant Code Example (Promotion):
In this noncompliant code example, the programmer intends to
shift a byte value two bits to the right (with zero fill). However, the
JLS specifies that the left operand must be promoted to either type
int or type long (int, in this case);

Compliant Code Example (Promotion):


This compliant solution uses a bitmask to clear the
Upper 24 bits (whose value was produced by sign
extension), generating the intended result.
The explicit cast to type int is redundant, but it clarifies the expected type.
Risk Assessment:
Incorrect use of shift operators can lead to unanticipated results, causing erratic
control flow or unanticipated program behavior.
Recommendations For Java

NUM Recommendation03:

• NUM52-J. Be aware of numeric promotion behavior

• NUM53-J. Use the strictfp modifier for floating-point


calculation consistency across platforms

• NUM54-J. Do not use denormalized numbers


Rec: NUM52-J. Be aware of numeric promotion
behavior
Numeric promotions:
 Numeric promotions are used to convert the operands of a numeric operator to a
common type so that an operation can be performed. When using arithmetic
operators with mixed operand sizes, narrower operands are promoted to the type
of the wider operand.

Promotion Rules:
Java Language Specification describes numeric promotion rules as follows:
• If any of the operands is of a reference type, unboxing conversion is performed.
• If either operand is of type double, the other is converted to double.
• Otherwise, if either operand is of type float, the other is converted to float.
• Otherwise, if either operand is of type long, the other is converted to long.
• Otherwise, both operands are converted to type int.
These conversions can occur when using the multiplicative operators (%, *, /),
additive operators (+, -), comparison operators (<, >, <=, >=), equality operators (==, !
=), and the integer bitwise operators (&, |, ^).
Examples:
In this example, a is promoted to a double before the + operator is applied

In this program fragment, b is first converted to int so that the + operator can be
applied to operands of the same type

The result of (a + b) is then converted to a float, and the comparison operator is


finally applied.
Compound Operators
• Type coercion may occur when compound expressions are used with mixed operand
types. Examples of compound assignment operators are +=, -=, *=, /=, &=, ^=, %=,
<<=, >>=, >>>=, and |=.
• A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)
((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

Noncompliant Code Example (Multiplication)


• In this noncompliant code example, a variable of the type
• int (big) is multiplied by a value of type float (one).

Noncompliant Code Example (Left Shift)


• This noncompliant code example shows an integer
• promotion resulting from the use of the bitwise OR operator.
Compliant Solution (Left Shift):
• This compliant solution masks off the upper 24 bits
of the byte array element to achieve the intended result

Noncompliant Code Example (Compound Addition and Assignment):


• The compound operation involves an int value that
contains too many significant bits to fit in the 23-bit
mantissa of a Java float, causing the widening
conversion from int to float to lose precision.
The resulting value is frequently unexpected.

Compliant Solution (Compound Addition and Assignment)


• For defensive programming purposes, avoid using any of the compound assignment
operators on variables of types byte, short, or char. Also, refrain from using a wider
operand on the right-hand side. In this compliant solution, all operands are of the Java
type double.
Noncompliant Code Example (Compound Bit Shift and Assignment):
• This noncompliant code example uses a compound
right-shift operator for shifting the value of i, bit.

Compliant Solution (Compound Bit Shift and Assignment):


• This compliant solution applies the compound assignment
operator to an int, which does not require widening and
subsequent narrowing. Consequently, I get the value 0x7fffffff.

Applicability
• Failing to consider integer promotions when dealing with floating-point and integer
operands can result in a loss of precision.

Automated Detection:
NUM53-J. Use the strictfp modifier for floating-point
calculation consistency across platforms
• Programs that require consistent results from floating-point operations across
different JVMs and platforms must use the strictfp modifier.
• It can have a substantial impact, however, on both the efficiency and the resulting
values of floating-point computations when executing on platforms that provide
extended floating-point support.
• On these platforms, using the strictfp modifier increases the likelihood that
intermediate operations will overflow or underflow because it restricts the range of
intermediate values that can be represented.
• It can also reduce computational efficiency.
• The strictfp modifier can be used with a class, method, or interface.
Non-Compliant Code Example

• This noncompliant code example does not mandate FP-strict computation.


Double.MAX_VALUE is multiplied by 1.1 and reduced back by dividing by 1.1,
according to the evaluation order. If Double.MAX_VALUE is the maximum value
permissible by the platform, the calculation will yield the result infinity.

• However, if the platform provides extended floating-point support, this program


might print a numeric result roughly equivalent to Double.MAX_VALUE.

• The JVM may choose to treat this case as FP-strict; if it does so, overflow occurs.
Because the expression is not FP-strict, an implementation may use an extended
exponent range to represent intermediate results.
Compliant Solution:

• For maximum portability, use the strictfp modifier within an expression (class,
method, or interface) to guarantee that intermediate results do not vary because
of implementation-defined behavior.
Non-Compliant Code Example

• Native floating-point hardware provides greater range than double. On these


platforms, the JIT is permitted to use floating-point registers to hold values of type
float or type double (in the absence of the strictfp modifier), even though the registers
support values with greater exponent range than that of the primitive types.
Consequently, conversion from float to double can cause an effective loss of
magnitude.
Compliant Solution:

• This compliant solution uses the strictfp keyword to require exact conformance with
the standard Java floating-point. Consequently, the intermediate value of both
computations of f * g is identical to the value stored in this.d, even on platforms that
support extended-range exponents.
Exceptions:

NUM06-J-EX0: This rule applies only to calculations that require consistent floating-
point results on all platforms. Applications that lack this requirement need not
comply.

Risk Assessment:
Failure to use the strictfp modifier can result in nonportable, implementation-defined
behavior with respect to the behavior of floating-point operations.
NUM54-J. Do not use denormalized numbers
• Java uses the IEEE 754 standard for floating-point representation.
• In this representation, floats are encoded using 1 sign bit, 8 exponent bits, and 23
mantissa bits.
• Doubles are encoded and used exactly the same way, except they use 1 sign bit, 11
exponent bits, and 52 mantissa bits.
• These bits encode the values of s, the sign; M, the significand; and E, the exponent.
• Floating-point numbers are then calculated as (-1)s * M * 2 E.

• Ordinarily, all of the mantissa bits are used to express significant figures, in addition to a
leading 1, which is implied and consequently omitted. As a result, floats have 24
significant bits of precision, and doubles have 53 significant bits of precision. Such
numbers are called normalized numbers.
• When the value to be represented is too small to encode normally, it is encoded in
denormalized form, indicated by an exponent value of Float.MIN_EXPONENT - 1 or
Double.MIN_EXPONENT - 1.

• Denormalized floating-point numbers have an assumed 0 in the ones' place and have
one or more leading zeros in the represented portion of their mantissa.

• These leading zero bits no longer function as significant bits of precision;


consequently, the total precision of denormalized floating-point numbers is less than
that of normalized floating-point numbers.

• Note that even using normalized numbers where precision is required can pose a risk.
Rule NUM04-J.

• Do not use floating-point numbers if precise computation is required for more


information.

• Using denormalized numbers can severely impair the precision of floating-point


calculations; as a result, denormalized numbers must not be used.
Detecting Denormalized Numbers

• The following code tests whether a float value is denormalized in FP-strict mode or for
platforms that lack extended-range support.

• Testing for denormalized numbers in the presence of extended-range support is


platform-dependent;
Print Representation of Denormalized Numbers:

• Denormalized numbers can also be troublesome because their printed representation


is unusual.

• Floats and normalized doubles, when formatted with the %a specifier, begin with a
leading nonzero digit. Denormalized doubles can begin with a leading zero to the left
of the decimal point in the mantissa.
Output:

• The Output demonstrates the print representation of denormalized numbers.

Noncompliant Code Example:


• This noncompliant code example attempts to reduce a floating-point number to a
denormalized value and then restore the value.
Output:

Exceptions:

NUM05-J-EX0: Denormalized numbers are acceptable when suitable numerical


analysis demonstrates that the computed values meet all accuracy and behavioral
requirements appropriate to the application.

Risk Assessment
Floating-point numbers are an approximation; denormalized floating-point numbers
are a less precise approximation. The use of denormalized numbers can cause an
unexpected loss of precision, possibly leading to incorrect or unexpected results.
Although the severity for violations of this rule is low, applications that require
accurate results should make every attempt to comply.

You might also like