From f6edd098a9adafa35c3b53491ec55b15b8bf3aed Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 16 Jun 2008 16:25:37 -0700 Subject: [PATCH] More file name and mode checks for $fopen{a,r,w}?. This patch adds checks that $fopen is only called with a valid mode argument. It also checks that the file name for $fopen{a,r,w}? is a valid looking file name (all characters satisfy isprint()). The later should prevent creating weird file names because of Verilog bugs. --- vpi/sys_fileio.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 9d705a82b..3d666a9d2 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -20,6 +20,7 @@ # include "vpi_user.h" # include "sys_priv.h" # include +# include # include # include # include @@ -91,6 +92,7 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) s_vpi_value val; int fail = 0; char *mode_string = 0; + unsigned idx; vpiHandle item = vpi_scan(argv); vpiHandle mode = vpi_scan(argv); @@ -103,10 +105,54 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s's mode argument was not a valid string.\n", + vpi_printf("%s's mode argument is not a valid string.\n", name); fail = 1; } + + /* Make sure the mode string is correct. */ + if (strlen(val.value.str) > 3) { + vpi_printf("WARNING: %s line %d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's mode argument (%s) is too long.\n", + name, val.value.str); + fail = 1; + } else { + unsigned bin = 0, plus = 0; + switch (val.value.str[0]) { + case 'r': + case 'w': + case 'a': + for (idx = 1; idx < 3 ; idx++) { + if (val.value.str[idx] == '\0') break; + switch (val.value.str[idx]) { + case 'b': + if (bin) fail = 1; + bin = 1; + break; + case '+': + if (plus) fail = 1; + plus = 1; + break; + default: + fail = 1; + break; + } + } + if (! fail) break; + + default: + vpi_printf("WARNING: %s line %d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's mode argument (%s) is invalid.\n", + name, val.value.str); + fail = 1; + break; + } + } + mode_string = strdup(val.value.str); vpi_free_object(argv); @@ -121,12 +167,31 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name) if (val.format != vpiStringVal || !*(val.value.str)) { vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s's file name argument was not a valid string.\n", + vpi_printf("%s's file name argument is not a valid string.\n", name); fail = 1; if (mode) free(mode_string); } + /* + * Verify that the file name is composed of only printable + * characters. + */ + unsigned len = strlen(val.value.str); + for (idx = 0; idx < len; idx++) { + if (! isprint(val.value.str[idx])) { + char msg [64]; + snprintf(msg, 64, "WARNING: %s line %d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s %s's file name argument contains non-" + "printable characters.\n", msg, name); + vpi_printf("%*s \"%s\"\n", strlen(msg), " ", val.value.str); + fail = 1; + if (mode) free(mode_string); + } + } + /* If either the mode or file name are not valid just return. */ if (fail) return 0; @@ -168,11 +233,29 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name) if (val.format != vpiStringVal || !*(val.value.str)) { vpi_printf("WARNING: %s line %d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s's file name argument was not a valid string.\n", + vpi_printf("%s's file name argument is not a valid string.\n", name); return 0; } + /* + * Verify that the file name is composed of only printable + * characters. + */ + unsigned idx, len = strlen(val.value.str); + for (idx = 0; idx < len; idx++) { + if (! isprint(val.value.str[idx])) { + char msg [64]; + snprintf(msg, 64, "WARNING: %s line %d:", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s %s's file name argument contains non-" + "printable characters.\n", msg, name); + vpi_printf("%*s \"%s\"\n", strlen(msg), " ", val.value.str); + return 0; + } + } + /* Open the file and return the result. */ val.format = vpiIntVal; val.value.integer = vpi_fopen(val.value.str, mode); @@ -616,19 +699,19 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name) val.format = vpiIntVal; switch (name[4]) { - case 'l': /* $ftell() */ + case 'l': /* $ftell() */ val.value.integer = ftell(fp); break; - case 'f': /* $feof() is from 1264-2005*/ + case 'f': /* $feof() is from 1264-2005*/ val.value.integer = feof(fp); break; - case 'i': /* $rewind() */ + case 'i': /* $rewind() */ val.value.integer = fseek(fp, 0L, SEEK_SET); break; - case 't': /* $fgetc() */ + case 't': /* $fgetc() */ val.value.integer = fgetc(fp); break; - default: + default: vpi_printf("ERROR: %s line %d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf("%s cannot be processed with this routine.\n", name);