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.
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
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).
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).
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:
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.
tnvfsgn should print:
TRAILING-PLUS 0007
TRAILING-MINUS 0007
LEADING-MINUS 0000
[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.
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.
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.