translated on 2017/04/15 from Japanese page on 2016/09/10
The latest libf2c.zip available at Netlib f2c (dated 26 September 2013) has several bugs.
This bug is applicable to ISO-8859-x characters. (not limited to 2-byte CJK characters)
Line | Source code to be amended | |
16-42 |
Original code |
static int i_getc(Void) { if(f__recpos >= f__svic->icirlen) { if (f__recpos++ == f__svic->icirlen) return '\n'; z_rnew(); } f__recpos++; if(f__icptr >= f__icend) return EOF; return(*f__icptr++); } static #ifdef KR_headers int i_ungetc(ch, f) int ch; FILE *f; #else int i_ungetc(int ch, FILE *f) #endif { if (--f__recpos == f__svic->icirlen) return '\n'; if (f__recpos < -1) err(f__svic->icierr,110,"recend"); /* *--icptr == ch, and icptr may point to read-only memory */ return *--f__icptr /* = ch */; } |
Amended |
static int i_getc(Void) { if(f__recpos >= f__svic->icirlen) { if (f__recpos++ == f__svic->icirlen) return '\n'; z_rnew(); } f__recpos++; if(f__icptr >= f__icend) return EOF; return((unsigned char)*f__icptr++); /* fix for 8bit char */ } static #ifdef KR_headers int i_ungetc(ch, f) int ch; FILE *f; #else int i_ungetc(int ch, FILE *f) #endif { if (--f__recpos == f__svic->icirlen) return '\n'; if (f__recpos < -1) err(f__svic->icierr,110,"recend"); /* *--icptr == ch, and icptr may point to read-only memory */ return (unsigned char)*--f__icptr /* = ch */; /* fix for 8bit char */ } |
The implicit cast from signed char to signed integer produces a negative integer due to the declaration extern char *f__icptr;
in case ch is greater than 127.
The result of this issue is system dependent on the implementation of `is-" macrofunction. For example in MS-VC++, Release build produces completely undefined behabior. Debug build produces an assersion at isdigit()
next to i_getc()
.
Changing to extern unsigned char *f__icptr;
is not recommended because of old style programming of f2c.
NOTE: iio.c contains return(*(unsigned char *)f__icptr++);
, i77vers.c contains follwoing comment. It might be a simple forgetting of rsli.c.
/* 24 Feb. 1995: iio.c: z_getc: insert (unsigned char *) to allow internal reading of characters with high-bit set (on machines that sign-extend characters). */
Line | Source code to be amended | |
54-64 |
Original code |
char f__ltab[128+1] = { /* offset one for EOF */ 0, 0,0,AX,0,0,0,0,0,0,WH|B,SX|WH,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, SX|B|WH,0,AX,0,0,0,0,AX,0,0,0,SG,SX,SG,0,SX, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, AX,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; |
Amended |
char f__ltab[256+1] = { /* offset one for EOF */ /* changed from 128 to 256 */ 0, 0,0,AX,0,0,0,0,0,0,WH|B,SX|WH,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, SX|B|WH,0,AX,0,0,0,0,AX,0,0,0,SG,SX,SG,0,SX, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, AX,0,0,0,EX,EX,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; |
Amendment of rsli.c leads to correct output of the macro GETC(ch)
for charcode 0-255; However, original f__ltab[]
has 128 contents and runs over.
Line 493 in original lread.c lets the pointer f__lchar
the address of allocated memory, however, the timing of `free' is not perfect and leads to a memory leak. This is unavoidable because of FORTRAN language's specification: "eating next lines when no suitable items is found".
This memory leak can be probed with MS-VC++ and following instructions.
Add to the beginning of f2c.h of libf2c source:
#ifdef _MSC_VER #define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> #endif
Add to the beginning of main.c of libf2c source:
#define _CRTDBG_MAP_ALLOC #include <crtdbg.h> #include <string.h> #include <windows.h>
Change the definition of main() in main.c of libf2c source: original:
modified:int #ifdef KR_headers main(argc, argv) int argc; char **argv; #else main(int argc, char **argv) #endif { xargc = argc; xargv = argv;
int #ifdef KR_headers main(argc, argv) int argc; char **argv; #else main(int argc, char **argv) #endif { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); _set_abort_behavior(0, _CALL_REPORTFAULT); // suppressing Dr.Watson clash dump _set_abort_behavior(1, _WRITE_ABORT_MSG); // enable error message to console (debug build only) _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); xargc = argc; xargv = argv;
Result:
Detected memory leaks! Dumping objects -> open.c(58) : {91} normal block at 0x00702868, 4096 bytes long. Data: < ] > 20 5D 0A 00 20 20 20 20 20 20 20 20 20 20 20 20 lread.c(501) : {87} normal block at 0x006FD7D0, 128 bytes long. Data: <0.2 > 30 2E 32 00 CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete.