Flawfinder version 2.0.10, (C) 2001-2019 David A. Wheeler.
Number of rules (primarily dangerous function names) in C/C++ ruleset: 223
Examining data/mupen64plus-ui-console-2.5.9/src/cheat.c
Examining data/mupen64plus-ui-console-2.5.9/src/cheat.h
Examining data/mupen64plus-ui-console-2.5.9/src/compare_core.c
Examining data/mupen64plus-ui-console-2.5.9/src/compare_core.h
Examining data/mupen64plus-ui-console-2.5.9/src/core_interface.h
Examining data/mupen64plus-ui-console-2.5.9/src/debugger.c
Examining data/mupen64plus-ui-console-2.5.9/src/debugger.h
Examining data/mupen64plus-ui-console-2.5.9/src/main.c
Examining data/mupen64plus-ui-console-2.5.9/src/osal_dynamiclib.h
Examining data/mupen64plus-ui-console-2.5.9/src/osal_dynamiclib_unix.c
Examining data/mupen64plus-ui-console-2.5.9/src/osal_dynamiclib_win32.c
Examining data/mupen64plus-ui-console-2.5.9/src/osal_files.h
Examining data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c
Examining data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c
Examining data/mupen64plus-ui-console-2.5.9/src/osal_preproc.h
Examining data/mupen64plus-ui-console-2.5.9/src/plugin.c
Examining data/mupen64plus-ui-console-2.5.9/src/plugin.h
Examining data/mupen64plus-ui-console-2.5.9/src/main.h
Examining data/mupen64plus-ui-console-2.5.9/src/core_interface.c
Examining data/mupen64plus-ui-console-2.5.9/src/version.h

FINAL RESULTS:

data/mupen64plus-ui-console-2.5.9/src/core_interface.c:153:17:  [4] (buffer) strcat:
  Does not check for buffer overflows when concatenating to destination
  [MS-banned] (CWE-120). Consider using strcat_s, strncat, strlcat, or
  snprintf (warning: strncat is easily misused).
                strcat(libPath, "/" OSAL_DEFAULT_DYNLIB_FILENAME);
data/mupen64plus-ui-console-2.5.9/src/debugger.c:164:9:  [4] (format) printf:
  If format strings can be influenced by an attacker, they can be exploited
  (CWE-134). Use a constant for the format specification.
        printf(regs[i] == 0 ? format_nopad : format_padded,
data/mupen64plus-ui-console-2.5.9/src/main.c:97:3:  [4] (format) vsnprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
  vsnprintf(msgbuf, 1024, message, args);
data/mupen64plus-ui-console-2.5.9/src/main.c:179:9:  [4] (format) vsnprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
		ret = vsnprintf(str, size, fmt, args);
data/mupen64plus-ui-console-2.5.9/src/main.c:308:13:  [4] (format) snprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
            snprintf(key, sizeof(key), key_fmt, i); \
data/mupen64plus-ui-console-2.5.9/src/main.c:309:13:  [4] (format) snprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
            snprintf(desc, sizeof(desc), desc_fmt, i); \
data/mupen64plus-ui-console-2.5.9/src/main.c:426:5:  [4] (buffer) strcpy:
  Does not check for buffer overflows when copying to destination [MS-banned]
  (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy
  easily misused).
    strcpy(ParsedString, ParamSpec);
data/mupen64plus-ui-console-2.5.9/src/main.h:25:88:  [4] (format) printf:
  If format strings can be influenced by an attacker, they can be exploited
  (CWE-134). Use a constant for the format specification.
extern void DebugMessage(int level, const char *message, ...)  __attribute__ ((format (printf, 2, 3)));
data/mupen64plus-ui-console-2.5.9/src/osal_files.h:37:11:  [4] (format) snprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
  #define snprintf _snprintf
data/mupen64plus-ui-console-2.5.9/src/osal_files.h:37:20:  [4] (format) _snprintf:
  If format strings can be influenced by an attacker, they can be exploited,
  and note that sprintf variations do not always \0-terminate (CWE-134). Use
  a constant for the format specification.
  #define snprintf _snprintf
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:52:5:  [4] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf.
    sprintf(pchSearchPath, "%s\\*.dll", searchpath);
data/mupen64plus-ui-console-2.5.9/src/osal_preproc.h:55:13:  [4] (format) printf:
  If format strings can be influenced by an attacker, they can be exploited
  (CWE-134). Use a constant for the format specification.
    #define printf(...) __android_log_print(ANDROID_LOG_VERBOSE, "UI-Console", __VA_ARGS__)
data/mupen64plus-ui-console-2.5.9/src/plugin.c:100:5:  [4] (buffer) strcpy:
  Does not check for buffer overflows when copying to destination [MS-banned]
  (CWE-120). Consider using snprintf, strcpy_s, or strlcpy (warning: strncpy
  easily misused).
    strcpy(g_PluginMap[MapIndex].filename, filepath);
data/mupen64plus-ui-console-2.5.9/src/osal_dynamiclib_win32.c:35:19:  [3] (misc) LoadLibrary:
  Ensure that the full path to the library is specified, or current directory
  may be used (CWE-829, CWE-20). Use registry entry or GetWindowsDirectory to
  find library path, if you aren't already.
    *pLibHandle = LoadLibrary(pccLibraryPath);
data/mupen64plus-ui-console-2.5.9/src/cheat.c:214:12:  [2] (misc) fopen:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
    fPtr = fopen(romdbpath, "rb");
data/mupen64plus-ui-console-2.5.9/src/cheat.c:363:5:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
    char RomSection[24];
data/mupen64plus-ui-console-2.5.9/src/cheat.c:364:5:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
    sprintf(RomSection, "%08X-%08X-C:%X", sl(l_RomHeader.CRC1), sl(l_RomHeader.CRC2), l_RomHeader.Country_code & 0xff);
data/mupen64plus-ui-console-2.5.9/src/compare_core.c:124:5:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
    char errHead[128];
data/mupen64plus-ui-console-2.5.9/src/compare_core.c:125:5:  [2] (buffer) sprintf:
  Does not check for buffer overflows (CWE-120). Use sprintf_s, snprintf, or
  vsnprintf. Risk is low because the source has a constant maximum length.
    sprintf(errHead, "Compare #%i  old_op: %x op: %x\n", comparecnt++, old_op, cur_opcode);
data/mupen64plus-ui-console-2.5.9/src/compare_core.c:221:17:  [2] (misc) fopen:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
        fPipe = fopen("compare_pipe", "r");
data/mupen64plus-ui-console-2.5.9/src/compare_core.c:226:17:  [2] (misc) fopen:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
        fPipe = fopen("compare_pipe", "w");
data/mupen64plus-ui-console-2.5.9/src/core_interface.c:150:13:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
            char libPath[1024 + 32];
data/mupen64plus-ui-console-2.5.9/src/debugger.c:191:5:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
    char input[256];
data/mupen64plus-ui-console-2.5.9/src/debugger.c:246:13:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
            char op[64];
data/mupen64plus-ui-console-2.5.9/src/debugger.c:247:13:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
            char args[64];
data/mupen64plus-ui-console-2.5.9/src/main.c:93:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char msgbuf[1024];
data/mupen64plus-ui-console-2.5.9/src/main.c:304:9:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
        char key[64];
data/mupen64plus-ui-console-2.5.9/src/main.c:305:9:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
        char desc[2048];
data/mupen64plus-ui-console-2.5.9/src/main.c:462:28:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
                ValueInt = atoi(VarValue);
data/mupen64plus-ui-console-2.5.9/src/main.c:511:33:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
            OutputList[idx++] = atoi(str);
data/mupen64plus-ui-console-2.5.9/src/main.c:669:27:  [2] (integer) atoi:
  Unless checked, the resulting number can exceed the expected range
  (CWE-190). If source untrusted, check both minimum and maximum, even if the
  input had no minus sign (large numbers can roll over into negative number;
  consider saving to an unsigned value if that is intended).
            int emumode = atoi(argv[i+1]);
data/mupen64plus-ui-console-2.5.9/src/main.c:779:5:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
    char value[4096];
data/mupen64plus-ui-console-2.5.9/src/main.c:830:5:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
    char key[64];
data/mupen64plus-ui-console-2.5.9/src/main.c:966:18:  [2] (misc) fopen:
  Check when opening files - can an attacker redirect it (via symlinks),
  force the opening of special file type (e.g., device files), move things
  around to create a race condition, control its ancestors, or change its
  contents? (CWE-362).
    FILE *fPtr = fopen(l_ROMFilepath, "rb");
data/mupen64plus-ui-console-2.5.9/src/osal_files.h:49:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char                     filepath[PATH_MAX];
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:41:9:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  const char *osal_libsearchpath[4] = { PLUGINDIR, "/usr/local/lib/mupen64plus",  "/usr/lib/mupen64plus", "./" };
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:44:9:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  const char *osal_libsearchpath[3] = { "/usr/local/lib/mupen64plus",  "/usr/lib/mupen64plus", "./" };
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:38:7:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
const char *osal_libsearchpath[1] = { ".\\" };
data/mupen64plus-ui-console-2.5.9/src/plugin.c:141:17:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
                char libPath[1024];
data/mupen64plus-ui-console-2.5.9/src/plugin.h:41:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char                name[8];
data/mupen64plus-ui-console-2.5.9/src/plugin.h:43:3:  [2] (buffer) char:
  Statically-sized arrays can be improperly restricted, leading to potential
  overflows or other issues (CWE-119!/CWE-120). Perform bounds checking, use
  functions that limit length, or ensure that the size is larger than the
  maximum possible length.
  char                filename[PATH_MAX];
data/mupen64plus-ui-console-2.5.9/src/cheat.c:258:34:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        char *endptr = curline + strlen(curline) - 1;
data/mupen64plus-ui-console-2.5.9/src/cheat.c:349:67:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
    if (CheatMode == CHEAT_DISABLE || (CheatMode == CHEAT_LIST && strlen(CheatNumList) == 0))
data/mupen64plus-ui-console-2.5.9/src/debugger.c:202:15:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        input[strlen(input) - 1] = 0;
data/mupen64plus-ui-console-2.5.9/src/debugger.c:532:18:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        else if (strlen(input) == 0)
data/mupen64plus-ui-console-2.5.9/src/main.c:213:17:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
    len_first = strlen(first);
data/mupen64plus-ui-console-2.5.9/src/main.c:420:36:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
    ParsedString = (char *) malloc(strlen(ParamSpec) + 1);
data/mupen64plus-ui-console-2.5.9/src/main.c:809:18:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
    size_t len = strlen(value);
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:67:36:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        if (strcmp(entry->d_name + strlen(entry->d_name) - strlen(suffix), suffix) != 0)
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:67:60:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        if (strcmp(entry->d_name + strlen(entry->d_name) - strlen(suffix), suffix) != 0)
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:88:9:  [1] (buffer) strncpy:
  Easily used incorrectly; doesn't always \0-terminate or check for invalid
  pointers [MS-banned] (CWE-120).
        strncpy(curr->filepath, searchpath, PATH_MAX-2);
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:90:28:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        if (curr->filepath[strlen(curr->filepath)-1] != '/')
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:91:13:  [1] (buffer) strcat:
  Does not check for buffer overflows when concatenating to destination
  [MS-banned] (CWE-120). Consider using strcat_s, strncat, strlcat, or
  snprintf (warning: strncat is easily misused). Risk is low because the
  source is a constant character.
            strcat(curr->filepath, "/");
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:92:23:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        int pathlen = strlen(curr->filepath);
data/mupen64plus-ui-console-2.5.9/src/osal_files_unix.c:94:9:  [1] (buffer) strncat:
  Easily used incorrectly (e.g., incorrectly computing the correct maximum
  size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf,
  or automatically resizing strings.
        strncat(curr->filepath, entry->d_name, PATH_MAX - pathlen - 1);
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:46:43:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
    char *pchSearchPath = (char *) malloc(strlen(searchpath) + 16);
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:81:9:  [1] (buffer) strncpy:
  Easily used incorrectly; doesn't always \0-terminate or check for invalid
  pointers [MS-banned] (CWE-120).
        strncpy(curr->filepath, searchpath, PATH_MAX-2);
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:83:28:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        if (curr->filepath[strlen(curr->filepath)-1] != '\\')
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:84:13:  [1] (buffer) strcat:
  Does not check for buffer overflows when concatenating to destination
  [MS-banned] (CWE-120). Consider using strcat_s, strncat, strlcat, or
  snprintf (warning: strncat is easily misused). Risk is low because the
  source is a constant character.
            strcat(curr->filepath, "\\");
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:85:29:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
        int pathlen = (int) strlen(curr->filepath);
data/mupen64plus-ui-console-2.5.9/src/osal_files_win32.c:87:9:  [1] (buffer) strncat:
  Easily used incorrectly (e.g., incorrectly computing the correct maximum
  size to add) [MS-banned] (CWE-120). Consider strcat_s, strlcat, snprintf,
  or automatically resizing strings.
        strncat(curr->filepath, entry.cFileName, PATH_MAX - pathlen - 1);
data/mupen64plus-ui-console-2.5.9/src/plugin.c:144:21:  [1] (buffer) strcat:
  Does not check for buffer overflows when concatenating to destination
  [MS-banned] (CWE-120). Consider using strcat_s, strncat, strlcat, or
  snprintf (warning: strncat is easily misused). Risk is low because the
  source is a constant character.
                    strcat(libPath, "/");
data/mupen64plus-ui-console-2.5.9/src/plugin.c:197:63:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
                    if (strncmp(curr->filename, cmdline_path, strlen(cmdline_path)) == 0)
data/mupen64plus-ui-console-2.5.9/src/plugin.c:213:40:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
            if (config_path != NULL && strlen(config_path) > 0)
data/mupen64plus-ui-console-2.5.9/src/plugin.c:229:66:  [1] (buffer) strlen:
  Does not handle strings that are not \0-terminated; if given one it may
  perform an over-read (it could cause a crash if unprotected) (CWE-126).
                        if (strncmp(curr->filename, config_path, strlen(config_path)) == 0)

ANALYSIS SUMMARY:

Hits = 65
Lines analyzed = 3925 in approximately 0.14 seconds (29049 lines/second)
Physical Source Lines of Code (SLOC) = 2811
Hits@level = [0] 114 [1]  24 [2]  27 [3]   1 [4]  13 [5]   0
Hits@level+ = [0+] 179 [1+]  65 [2+]  41 [3+]  14 [4+]  13 [5+]   0
Hits/KSLOC@level+ = [0+] 63.6784 [1+] 23.1234 [2+] 14.5856 [3+] 4.98043 [4+] 4.62469 [5+]   0
Dot directories skipped = 1 (--followdotdir overrides)
Minimum risk level = 1
Not every hit is necessarily a security vulnerability.
There may be other security vulnerabilities; review your code!
See 'Secure Programming HOWTO'
(https://dwheeler.com/secure-programs) for more information.