Menu ▾ ▴

#1284 TEST-NUMVAL family accepts 32 to 38 digits, and TEST-NUMVAL-F accepts a sign after the significand

GC 3.x
open
nobody
None
5 - default
2026-10-30
2026-10-30
No

TEST-NUMVAL, TEST-NUMVAL-C and TEST-NUMVAL-F report two kinds of input as valid when they are not. They accept a number with 32 to 38 digits, where the standard allows 31 with native arithmetic. TEST-NUMVAL-F also accepts a sign after the number, such as 123.45+, which its format does not allow. A program that uses these functions to validate input is told the input is fine.

To reproduce

tnv32.cob (attached) tests a 32-digit argument:

IDENTIFICATION DIVISION.
PROGRAM-ID. TNV32.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(4).
PROCEDURE DIVISION.
    MOVE FUNCTION TEST-NUMVAL("12345678901234567890123456789012")
      TO N
    DISPLAY "TEST-NUMVAL " N
    MOVE FUNCTION TEST-NUMVAL-C("12345678901234567890123456789012")
      TO N
    DISPLAY "TEST-NUMVAL-C " N
    STOP RUN.
cobc -x -free -std=cobol2014 -o tnv32 tnv32.cob && ./tnv32

What happens

A significand of 32 to 38 digits is accepted

Output on 3.2.0 (compile exit 0, run exit 0):

TEST-NUMVAL 0000
TEST-NUMVAL-C 0000

tnvlen.cob (attached) applies TEST-NUMVAL, TEST-NUMVAL-C and TEST-NUMVAL-F to 31, 32, 38 and 39 digits (PIC X(n) items holding 1234567890...). With the same command, the output is (exit 0):

31 TEST-NUMVAL   0000
31 TEST-NUMVAL-C 0000
31 TEST-NUMVAL-F 0000
32 TEST-NUMVAL-F 0000
38 TEST-NUMVAL   0000
38 TEST-NUMVAL-C 0000
38 TEST-NUMVAL-F 0000
39 TEST-NUMVAL   0039
39 TEST-NUMVAL-C 0039
39 TEST-NUMVAL-F 0039

3.3-dev r5751 gives byte-identical output from the same commands (exit 0).

TEST-NUMVAL-F accepts a sign after the significand

tnvfsgn.cob (attached):

IDENTIFICATION DIVISION.
PROGRAM-ID. TNVFSGN.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9(4).
PROCEDURE DIVISION.
    MOVE FUNCTION TEST-NUMVAL-F("123.45+") TO N
    DISPLAY "TRAILING-PLUS " N
    MOVE FUNCTION TEST-NUMVAL-F("123.45-") TO N
    DISPLAY "TRAILING-MINUS " N
    MOVE FUNCTION TEST-NUMVAL-F("-123.45") TO N
    DISPLAY "LEADING-MINUS " N
    STOP RUN.

Output of cobc -x -free -std=cobol2014 -o tnvfsgn tnvfsgn.cob && ./tnvfsgn on 3.2.0 (compile exit 0, run exit 0):

TRAILING-PLUS 0000
TRAILING-MINUS 0000
LEADING-MINUS 0000

3.3-dev r5751 gives byte-identical output with the same command (exit 0).

What should happen

31-digit limit

tnv32.cob should print TEST-NUMVAL 0032 and TEST-NUMVAL-C 0032. In tnvlen.cob, all three functions should give 0000 for 31 digits and 0032 for 32, 38 and 39 digits. ISO/IEC 1989:2023:

  • 11.9.5.2 rule 4: "If the ARITHMETIC clause is not specified in this source element or a containing source element, it is as if the ARITHMETIC clause were specified with the NATIVE phrase."
  • 15.67.3 rule 3 (NUMVAL) and 15.68.3 rule 6 (NUMVAL-C): "If native arithmetic is in effect, the total number of digits in argument-1 shall not exceed 31." 15.69.3 rule 2 (NUMVAL-F): "If native arithmetic is in effect, the total number of digits in the significand shall not exceed 31."
  • 15.93.4 rule 1 b) 2 (TEST-NUMVAL) and 15.94.4 rule 1 b) 2 (TEST-NUMVAL-C): "If native arithmetic is in effect, because the character in error for an argument that is greater than 31 digits is the 32nd digit, the returned value is the position of the 32nd digit if no prior error is found."
  • 15.95.4 rule 1 b) 2 (TEST-NUMVAL-F): "If native arithmetic is in effect, the argument contains a significand longer than 31 digits, and no prior error in the argument has been found, the returned value is the position of the 32nd digit of the significand".

The committee draft of the 2014 standard has the same 31-digit limits and gives the 32nd-digit position in NOTE 2 of each TEST-NUMVAL function. It applies the 31-digit limit to native and standard arithmetic alike.

Trailing sign in TEST-NUMVAL-F

tnvfsgn should print:

TRAILING-PLUS 0007
TRAILING-MINUS 0007
LEADING-MINUS 0000
  • 15.95.3 rule 1: "Argument-1 shall be an alphanumeric or national literal or a data item of class alphanumeric or national." Each call is valid whatever the content.
  • 15.95.4 rule 1: the returned value is 0 "If the content of argument-1 conforms to the argument rules for the NUMVAL-F function", and "Otherwise, if one or more characters are in error, the position of the first character in error".
  • 15.69.3 rule 1: "Argument-1 shall be an alphanumeric or national literal or data item whose content has the following format:" [space-string] [+|-] [space-string] {digit [. [digit]] | . digit} [space-string] [E [space-string] {+|-} [space-string] n [space-string]]. A sign is allowed only before the significand and after E, so in "123.45+" and "123.45-" the sign at position 7 is the first character in error. NUMVAL and NUMVAL-C do allow a trailing sign. NUMVAL-F does not.

The 2002 standard and the committee draft of the 2014 standard have the same NUMVAL-F format and the same TEST-NUMVAL-F returned-value rule.

Proposed fix

test-numval.patch (against 3.3-dev r5751, applies with patch -p1 at the top of the tree) changes libcob/intrinsic.c. The bodies of cob_check_numval and cob_check_numval_f become the static check_numval and check_numval_f, which take the maximum digit count as a parameter. cob_check_numval and cob_check_numval_f keep their signatures and pass COB_MAX_DIGITS, so their other callers (field validation in screenio.c, cob_put_field_str in call.c) keep the 38-digit limit. cob_intr_test_numval, cob_intr_test_numval_c and cob_intr_test_numval_f pass the new COB_NUMVAL_MAX_DIGITS_NATIVE (31), so they return the position of the 32nd digit.

In check_numval_f, a + or - after the first digit or decimal point is now an error unless it is the sign of the exponent, as the format in the comment above the function already states. This also applies to the other callers of cob_check_numval_f, while cob_intr_numval_f itself does not call it in the default build.

The patch changes behavior that the existing test FUNCTION TEST-NUMVAL-F (run_functions.at) pins. Its tests 6, 7, 8, 9, 12, 13 and 16 ("1 +", "1 -", "1 +-", "1 -+", "1.1 +", "1.1 -", "1.1 -CR") expected 0, 0, 4, 4, 0, 0 and 6, the values of a trailing sign accepted. The patch changes them to 3, 3, 3, 3, 5, 5 and 5, the position of the sign, per the format in 15.69.3 rule 1. These cases repeat the TEST-NUMVAL test above them, where a trailing sign is valid.

With the patch, cobc -x -free -std=cobol2014 and then the run both exit 0. tnv32.cob:

TEST-NUMVAL 0032
TEST-NUMVAL-C 0032

tnvlen.cob:

31 TEST-NUMVAL   0000
31 TEST-NUMVAL-C 0000
31 TEST-NUMVAL-F 0000
32 TEST-NUMVAL-F 0032
38 TEST-NUMVAL   0032
38 TEST-NUMVAL-C 0032
38 TEST-NUMVAL-F 0032
39 TEST-NUMVAL   0032
39 TEST-NUMVAL-C 0032
39 TEST-NUMVAL-F 0032

tnvfsgn.cob:

TRAILING-PLUS 0007
TRAILING-MINUS 0007
LEADING-MINUS 0000

make check on 3.3-dev r5751 with the patch: 1373 behaved as expected, 9 skipped, 0 failed (unpatched: 1372 behaved as expected, 9 skipped, 0 failed). The new test 1172 passes. The patch adds the test FUNCTION TEST-NUMVAL, TEST-NUMVAL-C, TEST-NUMVAL-F limits to tests/testsuite.src/run_functions.at, with entries in libcob/ChangeLog and tests/ChangeLog.

None found on the tracker.

Details

GnuCOBOL 3.2.0 (Ubuntu gnucobol3 3.2-4build1) and 3.3-dev r5751 (CI snapshot 3.3-dev.138 of 2026-10-29), x86_64 Linux, both re-run 2026-10-30. All three programs are free format. No program gets a cobc diagnostic. With 3.2.0 every cobc -x also prints two gcc lines from the Ubuntu package's build flags (<command-line>: warning: '_FORTIFY_SOURCE' redefined and its note); they are left out above.

4 Attachments

Discussion


Log in to post a comment.