Skip to content

Commit

Permalink
follow-up to [r5114] check for internal memory bounds with new flag "…
Browse files Browse the repository at this point in the history
…memory-check" (implied with --debug)

* increased fence to 8 bytes
* increased tests
* fixed CALL with BASED items to not use a fence
* doc update
  • Loading branch information
sf-mensch committed Jul 11, 2023
1 parent ccd3b7f commit 64b90e2
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 38 deletions.
30 changes: 15 additions & 15 deletions cobc/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1855,7 +1855,7 @@ output_call_cache (void)
/* note: we explicit do _not_ initialize it directly as that
will more likely lead to a non-consecutive memory layout,
which makes the whole purpose of the fence useless */
output_local ("static char\tcall_fence_pre[5];\n");
output_local ("static char\tcall_fence_pre[8];\n");
}
call_cache = call_list_reverse (call_cache);
for (call = call_cache; call; call = call->next) {
Expand All @@ -1869,7 +1869,7 @@ output_call_cache (void)
}
if ((call_cache || func_call_cache)
&& (cb_flag_memory_check & CB_MEMCHK_POINTER)) {
output_local ("static char\tcall_fence_post[5];\n");
output_local ("static char\tcall_fence_post[8];\n");
}
if (static_call_cache) {
const char *convention_modifier;
Expand Down Expand Up @@ -2094,10 +2094,10 @@ output_local_base_cache (void)
output_local ("static ");
}
#ifdef HAVE_ATTRIBUTE_ALIGNED
output_local ("cob_u8_t %s%d_fence_pre[5]%s;\n",
output_local ("cob_u8_t %s%d_fence_pre[8]%s;\n",
CB_PREFIX_BASE, fld->id, COB_ALIGN);
#else
output_local ("%scob_u8_t%s %s%d_fence_pre[5];\n",
output_local ("%scob_u8_t%s %s%d_fence_pre[8];\n",
COB_ALIGN_DECL_8, COB_ALIGN_ATTR_8,
CB_PREFIX_BASE, fld->id);
#endif
Expand Down Expand Up @@ -2129,10 +2129,10 @@ output_local_base_cache (void)
output_local ("static ");
}
#ifdef HAVE_ATTRIBUTE_ALIGNED
output_local ("cob_u8_t %s%d_fence_post[5]%s;\n",
output_local ("cob_u8_t %s%d_fence_post[8]%s;\n",
CB_PREFIX_BASE, fld->id, COB_ALIGN);
#else
output_local ("%scob_u8_t%s %s%d_fence_post[5];\n",
output_local ("%scob_u8_t%s %s%d_fence_post[8];\n",
COB_ALIGN_DECL_8, COB_ALIGN_ATTR_8,
CB_PREFIX_BASE, fld->id);
#endif
Expand Down Expand Up @@ -2165,13 +2165,13 @@ output_nonlocal_base_cache (void)

if (fld->flag_used_in_call) {
#ifdef HAVE_ATTRIBUTE_ALIGNED
output_storage ("static cob_u8_t %s%d_fence_pre[5]%s;\n",
output_storage ("static cob_u8_t %s%d_fence_pre[8]%s;\n",
CB_PREFIX_BASE, fld->id, COB_ALIGN);
#else
#if defined(COB_ALIGN_PRAGMA_8)
output_storage ("#pragma align 8 (%s%d_fence_pre)\n", CB_PREFIX_BASE, fld->id);
#endif
output_storage ("static %scob_u8_t%s %s%d_fence_pre[5];\n",
output_storage ("static %scob_u8_t%s %s%d_fence_pre[8];\n",
COB_ALIGN_DECL_8, COB_ALIGN_ATTR_8,
CB_PREFIX_BASE, fld->id);
#endif
Expand Down Expand Up @@ -2200,13 +2200,13 @@ output_nonlocal_base_cache (void)
output_storage ("\t/* %s */\n", fld->name);
if (fld->flag_used_in_call) {
#ifdef HAVE_ATTRIBUTE_ALIGNED
output_storage ("static cob_u8_t %s%d_fence_post[5]%s;\n",
output_storage ("static cob_u8_t %s%d_fence_post[8]%s;\n",
CB_PREFIX_BASE, fld->id, COB_ALIGN);
#else
#if defined(COB_ALIGN_PRAGMA_8)
output_storage ("#pragma align 8 (%s%d_fence_post)\n", CB_PREFIX_BASE, fld->id);
#endif
output_storage ("static %scob_u8_t%s %s%d_fence_post[5];\n",
output_storage ("static %scob_u8_t%s %s%d_fence_post[8];\n",
COB_ALIGN_DECL_8, COB_ALIGN_ATTR_8,
CB_PREFIX_BASE, fld->id);
#endif
Expand Down Expand Up @@ -6462,12 +6462,12 @@ output_memory_check_call (struct cb_call *p, const enum cob_statement stmt)
const struct cb_field *fchck = cb_field_founder (CB_FIELD (x));
if (fchck->flag_used_in_call) {
if (stmt == STMT_BEFORE_CALL) {
output_line ("if (memcmp (%s%d_fence_pre, \"\\x00\\x00\\x00\\x00\", 5) == 0) {",
output_line ("if (memcmp (%s%d_fence_pre, \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\", 8) == 0) {",
CB_PREFIX_BASE, fchck->id);
output_indent_level += indent_adjust_level;
output_line ("memcpy (%s%d_fence_pre, \"\\xFF\\xFE\\xFD\\xFC\", 5);",
output_line ("memcpy (%s%d_fence_pre, \"\\xFF\\xFE\\xFD\\xFC\\xFB\\xFA\\xFF\", 8);",
CB_PREFIX_BASE, fchck->id);
output_line ("memcpy (%s%d_fence_post, \"\\xFA\\xFB\\xFC\\xFD\", 5);",
output_line ("memcpy (%s%d_fence_post, \"\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\\xFA\", 8);",
CB_PREFIX_BASE, fchck->id);
output_indent_level -= indent_adjust_level;
output_line ("} else {");
Expand Down Expand Up @@ -12523,8 +12523,8 @@ output_internal_function (struct cb_program *prog, cb_tree parameter_list)
if ((call_cache || func_call_cache)
&& (cb_flag_memory_check & CB_MEMCHK_POINTER)) {
output_line ("/* Initialize call-pointer memory fence */");
output_line ("memcpy (call_fence_pre, \"\\xFF\\xFE\\xFD\\xFC\", 5);");
output_line ("memcpy (call_fence_post, \"\\xFA\\xFB\\xFC\\xFD\", 5);");
output_line ("memcpy (call_fence_pre, \"\\xFF\\xFE\\xFD\\xFC\\xFB\\xFA\\xFF\", 8);");
output_line ("memcpy (call_fence_post, \"\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\\xFA\", 8);");
output_newline ();
}

Expand Down
4 changes: 2 additions & 2 deletions cobc/codeoptim.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ cob_gen_optim (const enum cb_optim val)
output_storage ("cob_check_fence_inline (const char *fence_pre, const char *fence_post,");
output_storage (" const enum cob_statement stmt, const char *name)");
output_storage ("{");
output_storage (" if (memcmp (fence_pre, \"\\xFF\\xFE\\xFD\\xFC\", 5)");
output_storage (" || memcmp (fence_post, \"\\xFA\\xFB\\xFC\\xFD\", 5)) {");
output_storage (" if (memcmp (fence_pre, \"\\xFF\\xFE\\xFD\\xFC\\xFB\\xFA\\xFF\", 8)");
output_storage (" || memcmp (fence_post, \"\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF\\xFA\", 8)) {");
output_storage (" cob_check_fence (fence_pre, fence_post, stmt, name);");
output_storage (" }");
output_storage ("}");
Expand Down
3 changes: 2 additions & 1 deletion cobc/typeck.c
Original file line number Diff line number Diff line change
Expand Up @@ -8798,7 +8798,8 @@ cb_emit_call (cb_tree prog, cb_tree par_using, cb_tree returning,
if ((cb_flag_memory_check & CB_MEMCHK_USING)
&& f->storage != CB_STORAGE_LINKAGE
&& f->storage != CB_STORAGE_LOCAL
&& !f->flag_external) {
&& !f->flag_external
&& !f->flag_item_based) {
f = cb_field_founder (f);
if (f->redefines) {
f = f->redefines;
Expand Down
7 changes: 6 additions & 1 deletion doc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@

2023-07-10 Simon Sobisch <[email protected]>

* gnucobol.texi: updated "Build target" (change of -P / -E),
updated "Debug switches" (changed -g and new memory-check)

2023-05-24 Simon Sobisch <[email protected]>

* gnucobol.texi: document warning and optimization options
related to unreachable code; add node on core dumps
related to unreachable code; add note on core dumps

2023-01-31 Fabrice Le Fessant <[email protected]>

Expand Down
22 changes: 17 additions & 5 deletions doc/gnucobol.texi
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ The special input name @file{-} takes input from @file{stdin} which is
assumed to be COBOL source, and uses a default output name of
@file{a.out} (or @file{a.so/c/o/i}, selected as appropriate) for the build type.

You may also use @file{-} as output name for the listing file or the preprocessor
result, for example with @code{cobc -t - prog.cob} / @code{cobc -P- prog.cob}.

By default, the compiler builds a dynamically loadable module.

The following options specify the target type produced by the compiler:
Expand All @@ -361,12 +364,17 @@ The following options specify the target type produced by the compiler:
@item -E
Preprocess only: compiler directives are executed, comment lines are
removed and @code{COPY} statements are expanded.
The output is saved in file @file{*.i}.
The output is sent to stdout, allowing you to directly use it as input for
another process. You can manually set an output file using @option{-o}.

@item -C
Translation only. COBOL source files are translated into C files.
The output is saved in file @file{*.c}.

@item --save-temps
Normal compilation with additional storing the preprocessed files as @file{*.i}
and the translated C files as file @file{*.c}.

@item -S
Compile only. Translated C files are compiled by the C compiler
to assembler code. The output is saved in file @file{*.s}.
Expand Down Expand Up @@ -878,13 +886,17 @@ Produce C debugging information in the output.
@item --debug, -d
Enable all run-time error checks.

@item -fmemory-check=scope
Enable checking of internal storage during CALL (implied by @option{--debug}.

@item -fec=exception-name, -fno=ec=exception-name
Enable/disable specified exception checks,
@pxref{Appendix F, Exception Names, Exception Names}.
@pxref{Appendix F, Exception Names, Exception Names};
@option{--debug} implies @option{-fec=ALL}.

@item -fsource-location
Generate source location code (implied by @option{--debug}, @option{-g} and
@option{-fec}); @option{--debug} implies @option{-fec=ALL}.
Generate source location code (implied by @option{--debug}, @option{-fdump} and
@option{-fec}).

@item -fstack-check
Enable @code{PERFORM} stack checking (implied by @option{--debug} or @option{-g}).
Expand Down Expand Up @@ -1692,7 +1704,7 @@ In addition, setting the option @code{binary-size} to @code{2-4-8} or

The compiler option @option{--debug} can be used, especially during the
development of your programs. It enables all run-time error checking, such as
subscript boundary checks and numeric data checks, and displays
subscript boundary checks and numeric data checks, and leads to display of
run-time errors with source locations.
Exceptions may also be enabled/disabled separately.
@xref{Debug switches, Debug switches,,,}.
Expand Down
4 changes: 2 additions & 2 deletions libcob/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -4150,8 +4150,8 @@ void
cob_check_fence (const char *fence_pre, const char *fence_post,
const enum cob_statement stmt, const char *name)
{
if (memcmp (fence_pre, "\xFF\xFE\xFD\xFC", 5)
|| memcmp (fence_post, "\xFA\xFB\xFC\xFD", 5)) {
if (memcmp (fence_pre, "\xFF\xFE\xFD\xFC\xFB\xFA\xFF", 8)
|| memcmp (fence_post, "\xFA\xFB\xFC\xFD\xFE\xFF\xFA", 8)) {
/* LCOV_EXCL_START */
if (name) {
/* note: reserved, currently not generated in libcob */
Expand Down
37 changes: 25 additions & 12 deletions tests/testsuite.src/run_misc.at
Original file line number Diff line number Diff line change
Expand Up @@ -14113,14 +14113,26 @@ AT_DATA([caller.cob], [
DATA DIVISION.
WORKING-STORAGE SECTION.

01 var PIC x.
01 var PIC X.

01 varg PIC X GLOBAL.
01 vare PIC X EXTERNAL.
01 varb PIC X BASED.
LINKAGE SECTION.
01 varl PIC X.

PROCEDURE DIVISION.
*
CALL "callee" USING var
* without the check this second call would SIGSEGV
CALL "callee" USING var

* the following are mostly in to co-test the codegen
CALL "callee" USING varg
CALL "callee" USING vare
CALL "callee" USING varb
CALL "callee" USING varl

GOBACK.
])

Expand All @@ -14147,22 +14159,22 @@ AT_DATA([callee.cob], [
AT_CHECK([$COMPILE -fno-ec=program-arg-mismatch -fmemory-check=pointer caller.cob], [0], [], [])
AT_CHECK([$COMPILE_MODULE -fno-ec=program-arg-mismatch callee.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./caller], [1], [],
[libcob: caller.cob:12: error: memory violation detected after CALL
[libcob: caller.cob:18: error: memory violation detected after CALL
])

AT_CHECK([$COMPILE -fno-ec=program-arg-mismatch -fmemory-check=using caller.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./caller], [1], [],
[libcob: caller.cob:12: error: memory violation detected for 'var' after CALL
[libcob: caller.cob:18: error: memory violation detected for 'var' after CALL
])

AT_CHECK([$COMPILE -fno-ec=program-arg-mismatch -fmemory-check caller.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./caller], [1], [],
[libcob: caller.cob:12: error: memory violation detected for 'var' after CALL
[libcob: caller.cob:18: error: memory violation detected for 'var' after CALL
])

AT_CHECK([$COMPILE -fno-ec=program-arg-mismatch -fmemory-check=all caller.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./caller], [1], [],
[libcob: caller.cob:12: error: memory violation detected for 'var' after CALL
[libcob: caller.cob:18: error: memory violation detected for 'var' after CALL
])

AT_CLEANUP
Expand All @@ -14184,21 +14196,22 @@ AT_DATA([prog.cob], [
DATA DIVISION.
WORKING-STORAGE SECTION.

77 PNT USAGE POINTER EXTERNAL.

01 REC.
03 VAR PIC X(16).
03 VAR2 PIC X(16).
77 PNT USAGE POINTER.
03 VAR PIC X.
03 VAR2 PIC X.

LINKAGE SECTION.
01 LREC.
03 LVAR PIC X(32).
03 LVAR2 PIC X(32).
03 LVAR PIC X(64).
03 LVAR2 PIC X(64).

PROCEDURE DIVISION.
* using a (not working) call prevents the C compiler
* to know that we (do not) change the pointer variable
* and therefore disallows it to check
* "that points to VAR2, you only have 32 bytes" (done with gcc -O)
* "that points to VAR2, you only have 2 bytes" (done with gcc -O)
SET PNT TO ADDRESS OF VAR2.
CALL "notthere" USING PNT ON EXCEPTION CONTINUE.
SET ADDRESS OF LREC TO PNT.
Expand All @@ -14210,7 +14223,7 @@ AT_DATA([prog.cob], [

AT_CHECK([$COMPILE prog.cob], [0], [], [])
AT_CHECK([$COBCRUN_DIRECT ./prog], [1], [],
[libcob: prog.cob:27: error: memory violation detected after INIT CALL
[libcob: prog.cob:28: error: memory violation detected after INIT CALL
])

AT_CLEANUP
Expand Down

0 comments on commit 64b90e2

Please sign in to comment.