I have C two functions doing exactly the same thing. The only difference is their return type and first argument type:
int func1(int a, int *b) {
if (a > 0) {
*b = 0;
return 1;
}
*b = -1;
return 0;
}
double func2(double a, int *b) {
if (a > (double)0.0) {
*b = 0;
return 1.0;
}
*b = -1;
return (double)0.0;
}
Compiling them to the library:
gcc -c -static -o testlib.o testlib.c
The following COBOL code calls both functions:
IDENTIFICATION DIVISION.
PROGRAM-ID. CallCFunctions.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 VAR-AI USAGE BINARY-SHORT SIGNED.
01 VAR-BI USAGE BINARY-SHORT SIGNED.
01 VAR-CI USAGE BINARY-SHORT SIGNED.
01 VAR-AD USAGE BINARY-DOUBLE.
01 VAR-BD USAGE BINARY-DOUBLE.
01 VAR-CD USAGE BINARY-DOUBLE.
PROCEDURE DIVISION.
MOVE 1 TO VAR-AI.
MOVE -10 TO VAR-BI.
MOVE ZERO TO VAR-CI.
CALL "func1" USING BY VALUE VAR-AI BY REFERENCE VAR-BI
RETURNING VAR-CI
DISPLAY "Calling 'func1'".
DISPLAY "A = ", VAR-AI, " B = ", VAR-BI, " C = ", VAR-CI
MOVE 1 TO VAR-AD.
MOVE -10 TO VAR-BD.
MOVE ZERO TO VAR-CD.
CALL "func2" USING BY VALUE VAR-AD BY REFERENCE VAR-BD
RETURNING VAR-CD
DISPLAY "Calling 'func2'".
DISPLAY "A = ", VAR-AD, " B = ", VAR-BD, " C = ", VAR-CD
STOP RUN.
Compiling COBOL code:
cobc -x -free -o test test.cbl testlib.o
The first function works but the second generates an error:
attempt to reference unallocated memory (signal SIGSEGV) Full output
Calling 'func1'
A = +00001 B = +00000 C = +00001
Calling 'func2'
attempt to reference unallocated memory (signal SIGSEGV)
Could anyone explain what seems to be the problem?
Your declared variable types (USAGE
) in the COBOL source are not compatible with those in the C source.
First, the BINARY-DOUBLE
type in GnuCobol is a 64-bit, native integer. From the GnuCOBOL Programmer’s Guide:
BINARY-DOUBLE [ SIGNED ]
~~~~~~~~~~~~~
Range of Values: -9,223,372,036,854,775,808 – 9,223,372,036,854,775,807
Storage Format: Native Binary Integer
What you want, if you're after the IEEE-754 64-bit floating point type (as is the C double
) is FLOAT-LONG
. From the same document:
FLOAT-LONG
~~~~~~~~~~
Range of Values: Approx. -1.797693134862316 * 10308 – 1.797693134862316 * 10308
Storage Format: Native IEEE 754 Binary64 Floating-point
However, I can't see that this – of itself – would cause the reported SIGSEGV
error, as both memory 'units' have the same size (although the passed a
value will be interpreted as a nonsense double
).
What's more likely causing that memory violation is that the type of the int
arguments are also wrong: BINARY-SHORT
is a 16 bit integer but the C int
is 32 bits (see the same, linked document).
You need to:
BINARY-LONG
(or BINARY-INT
) type in your COBOL code;short
type for your arguments and return type in your C code.As it stands, your C functions are writing (or attempting to write) 32 bits to a location that's only guaranteed to be 16 bits in size; this is undefined behaviour and is more likely the cause of the error. [You're just (un)lucky that, in the func1
call, that UB didn't trigger the memory violation!]