无法在 C 中找到内存泄漏
Cant find memory leak in C
在我发现某处有一段记忆 leak/error 之后,我已经坐了几个小时来检查这段代码
哪里漏了?如何修复?
这是 Dr.Memory 报告:
Dr. Memory version 2.3.0
Running "C:\Users\Beni\source\repos\Magshimim_EX8\Debug\Magshimim_EX8.exe"
Using system call file C:\Users\Beni\AppData\Roaming\Dr. Memory\symcache\syscalls_wow64.txt
Error #1: UNADDRESSABLE ACCESS: reading 1 byte(s)
replace_strlen
d:\drmemory_package\drmemory\replace.c(412):
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
KERNEL32.dll!BaseThreadInitThunk
??:0
ERRORS FOUND:
1 unique, 1 total unaddressable access(es)
0 unique, 0 total uninitialized access(es)
0 unique, 0 total invalid heap argument(s)
0 unique, 0 total GDI usage error(s)
0 unique, 0 total handle leak(s)
0 unique, 0 total warning(s)
0 unique, 0 total, 0 byte(s) of leak(s)
0 unique, 0 total, 0 byte(s) of possible leak(s)
Details: C:\Users\Beni\AppData\Roaming\Dr. Memory\DrMemory-Magshimim_EX8.exe.5208.000\results.txt
WARNING: application exited with abnormal code 0xc0000005
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#define FALSE 0
#define TRUE !FALSE
#define FIRST_TWO_FILES 2
#define FIRST_TWENTY_PRECENTS 1
#define MIDDLE_SIXTY_PRECENTS 2
#define LAST_TWENTY_PRECENTS 3
long findLenOfFile(FILE * file);
char* readFile(FILE* f, char* dest, long len);
char menu(char* scanFolder, char* virusSignature);
char** writeFilesFromFolder(char* scanFolder, char ** filesList, int* len);
char* writePart(char* src, char* dest, int length, int* newLen, int part);
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen);
void scanFiles(char* scanFolder, char** filesList, int amountOfFiles, char* virusSignature, long virusLength, char option);
int main(int argc, char* argv[])
{
char* log = malloc(sizeof(char)*strlen(argv[1]) + sizeof(char)*strlen("\Log.txt") + 4);
FILE* virusSignatureFile = fopen(argv[2], "rb");
long virusLength = 0;
char** filesList = (char**)malloc(sizeof(char) * 0);
char* virusSignature = 0;
int amountOfFiles = 0;
char option = 0;
int i = 0;
virusLength = findLenOfFile(virusSignatureFile);
// get the virusSignature as a string and write the files to check into the filesList
virusSignature = readFile(virusSignatureFile, virusSignature, virusLength);
filesList = writeFilesFromFolder(argv[1], filesList, &amountOfFiles);
// create log file
strcpy(log, "");
strcat(log, argv[1]);
strcat(log, "\Log.txt");
FILE * logFile = fopen(log, "w");
fprintf(logFile, "Anti-virus began! Welcome!\n\nFolder to scan:\n%s\nVirus signature:\n%s\n\nScanning option:\n", argv[1], argv[2]);
// get scanning option (normal or quick) and continue accordingly
option = menu(argv[1], argv[2]);
if (option == '0') {
fprintf(logFile, "Normal Scan\n\n");
}
else {
fprintf(logFile, "Quick Scan\n\n");
}
fprintf(logFile, "Results:\n");
fclose(logFile);
// initiate scan
scanFiles(argv[1], filesList, amountOfFiles, virusSignature, virusLength, option);
fclose(virusSignatureFile);
free(log);
free(filesList);
free(virusSignature);
getchar();
return 0;
}
/*
This function will print the scanning folder path and signature path, also will print the option menu to the user of quick or normal scan,
after that function will return user option(0, or other key)
input: scanFolder path (string), virus signature path (also string)
output: user option (char: '0', or other key)
*/
char menu(char * scanFolder, char * virusSignature)
{
char userOption = '[=11=]';
printf("Welcome to my Virus Scan!\n\nFolder to scan: %s\nVirus signature: %s\n\nPress 0 for a norman scan or any other key for a quick scan: ", scanFolder, virusSignature);
userOption = getchar();
printf("Scanning began...\nThis process may take several minutes...\n\n");
return userOption;
}
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char** writeFilesFromFolder(char * scanFolder, char ** filesList, int* len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = 0;
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (i > 1)
{
filesList = (char**)realloc(filesList, sizeof(filesList) + sizeof(char*) + 4);
*(filesList + (i - FIRST_TWO_FILES)) = (char*)malloc(sizeof(char) * strlen(dir->d_name) + 1);
strcpy(*(filesList + (i - FIRST_TWO_FILES)), (dir->d_name));
}
i++;
}
closedir(d);
}
*len = i - FIRST_TWO_FILES; //first two names is "." and ".."
return filesList;
}
/*
This function will read the contents of a file into a string
input: a file (FILE *) to read from
output: char* with the contents of the file
*/
char* readFile(FILE* f, char * dest, long len)
{
dest = (char*)malloc(sizeof(char) * len);
fread(dest, 1, len, f);
return dest;
}
void scanFiles(char * scanFolder, char ** filesList, int amountOfFiles, char * virusSignature, long virusLength, char option)
{
char* log = malloc(sizeof(char)*strlen(scanFolder) + sizeof(char)*strlen("\Log.txt") + 1);
char * buffer = (char*)malloc(sizeof(char) * 0);
char* subBuffer = 0;
char* slash = "\";
long length = 0;
char* name = 0;
int subLen = 0;
int i = 0;
FILE * f;
// reopen log file and append to it
strcpy(log, "");
strcat(log, scanFolder);
strcat(log, "\Log.txt");
FILE * logFile = fopen(log, "a");
// iterate over each file
for (i = 0; i < amountOfFiles; i++)
{
name = (char*)malloc(sizeof(char) * strlen(scanFolder) + 1 + sizeof(char) * strlen(slash) + sizeof(char) * strlen(*(filesList + i)) + 20);
// open current file
strcpy(name, "");
strcat(name, scanFolder);
strcat(name, slash);
strcat(name, *(filesList + i));
f = fopen(name, "rb");
length = findLenOfFile(f);
if (f != NULL) // if file can be accessed
{
buffer = readFile(f, buffer, length);
if (option == '0') { // Normal Mode
if (findSignature(virusSignature, buffer, virusLength, length))
{
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else
{
printf("%s - Clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
else { // Quick Mode
subBuffer = writePart(buffer, subBuffer, length, &subLen, FIRST_TWENTY_PRECENTS); // get first 20%
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - infected! (first 20%%)\n", name);
fprintf(logFile, "%s - infected! (first 20%%)\n", name);
}
else {
free(subBuffer);
subBuffer = writePart(buffer, subBuffer, length, &subLen, LAST_TWENTY_PRECENTS); // get last 20%
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - Infected! (last 20%%)\n", name);
fprintf(logFile, "%s - Infected! (last 20%%)\n", name);
}
else {
subBuffer = writePart(buffer, subBuffer, length, &subLen, MIDDLE_SIXTY_PRECENTS); // get the 60% left in the middle
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
}
free(subBuffer);
}
fclose(f);
}
else
{
printf("No file found\n");
}
free(*(filesList + i));
free(name);
}
fclose(logFile);
free(log);
free(buffer);
getchar();
}
/*
This function will write part of the file (beginning, middle or end) to a string
input: source (string) to take the information from, destination (string) to write a part of the source to it,
length (int) of the source string, a pointer (int*) to store the new length of the destination string and
part of the file to write from (int) 1,2 or 3: first 20%, 60% in the middle and last 20% accordingly
output: string containing the desired part of the source string
*/
char* writePart(char *src, char *dest, int length, int *newLen, int part) {
int i = 0;
int percentedLength = 0;
int count = 0;
percentedLength = (int)(length / 5); // this len is 20% of the entire file's length
if (part == FIRST_TWENTY_PRECENTS) // return beginning
{
dest = (char*)malloc(sizeof(char) * percentedLength);
*newLen = percentedLength;
for (i = 0; i < percentedLength; i++)
{
*(dest + i) = *(src + i);
}
}
else if (part == MIDDLE_SIXTY_PRECENTS) // return middle
{
// allocate space for the middle: The entire file size minus 20% from the start and 20% from the end
dest = (char*)malloc(sizeof(char) * (length - 2 * percentedLength));
*newLen = length - 2 * percentedLength;
for (i = percentedLength; i < length - percentedLength; i++) {
*(dest + count) = *(src + i);
count++;
}
}
else if (part == LAST_TWENTY_PRECENTS) // return end
{
dest = (char*)malloc(sizeof(char) * percentedLength);
*newLen = percentedLength;
for (i = length - percentedLength; i < length; i++)
{
*(dest + count) = *(src + i);
count++;
}
}
return dest;
}
/*
function that finds the length of a file
input: file (FILE *)
output: the file's length (long)
*/
long findLenOfFile(FILE * file)
{
long length = 0;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
/*
function checks whether a file contains the virusSignature. It iterates over each letter of the file and checks
if it is the same as the first letter in the virusSignature. If it is, it checks the rest of the characters and
returns True if a match is found. if not it continues the same process until the end of the file is reached.
input: The virusSignature (string), a buffer with the content of a file (string), the signature's length (int)
and the buffer's length (int)
output: True if signature is in file, False otherwise
*/
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen)
{
int found = 0;
int i = 0;
int j = 0;
for (i = 0; i < bufferLen - (sigLen - 1); i++) {
if (*(buffer + i) == *virusSignature) // check if a letter is the same as first letter in virusSignature
{
found = TRUE;
// check if the rest of the letters match the signature and stop if one doesn't
for (j = 1; (j < sigLen) && found; j++) {
if (*(buffer + (i + j)) != *(virusSignature + j)) {
found = FALSE;
}
}
if (found) {
return TRUE; // if we got a match, return true!
}
}
}
return FALSE;
}
writeFilesFromFolder
中的 realloc
调用有错误。
是:
filesList = (char **) realloc(filesList, sizeof(filesList) + sizeof(char *) + 4);
请注意分配给 filesList
的 space 是 常量 。随着新元素的添加,它不会增长,因此您有未定义的行为。
这不是工具检测到的内存泄漏。内存泄漏意味着您无法 free
超出范围的指针。
相反,您存储的数据超出了您分配的区域的末尾,破坏了那里的所有内容,这可能是 malloc
等的 [隐藏] 链指针区域。阿尔。用于跟踪分配。
我不确定 sizeof
中的任何一个因素,但是,filesList
是一个指针,所以 sizeof(filesList)
是常量 [在 32 位机器上为 4 或者8 表示 64 位。
分配的space必须按比例增加到i
。
这是该函数的重构版本,它修复了错误并进行了一些简化和清理:
顺便说一句,不要投malloc
:Do I cast the result of malloc?
此外,请注意 sizeof(char)
[根据定义] 始终 1,无论 char
对于给定架构实际具有多少位。因此,删除任何 sizeof(char) *
而不是(例如):
*(filesList + i)
通常simpler/cleaner要做:
filesList[i]
无论如何,这是代码:
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char **
writeFilesFromFolder(char *scanFolder, char **filesList, int *len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = -FIRST_TWO_FILES;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (i >= 0) {
filesList = realloc(filesList,sizeof(*filesList) * (i + 1));
filesList[i] = strdup(dir->d_name);
}
i++;
}
closedir(d);
}
*len = i; // first two names is "." and ".."
return filesList;
}
更新:
好的,你确实有内存泄漏。而且,我编写了检测和修复程序。
首先,您所做的是将缓冲区指针作为参数(例如dest
)传递给函数(例如readFile
或writePart
)。
那么,你在做:
dest = malloc(percentedLength);
这个 泄漏 dest
的 以前的 值。
通常,分配缓冲区的函数 return 它 而不是 将其作为参数。但是,在分析您的代码后,将 malloc
替换为 realloc
可以防止泄漏。
我必须进行完整的代码审查才能找到它。而且,我在此过程中进行了几次简化和清理,以尝试理解您的代码并隔离可能的进一步问题。
我用新函数 filejoin
替换了你的 allocation/concatenation 个文件名。
我用宏替换了其他 malloc
调用:ALLOCME
检测内存泄漏 在 发生之前。这与替换 free
调用的 [new] FREEME
宏结合使用。
默认模式是检测泄漏并中止。如果你给程序一个 -f
选项,它会解决这个问题。在你分析明白发生了什么之后,你可以把默认的改为"fix"模式。
在可能的情况下,我将您的原始代码留在 #if 0
下
更多风格提示:
保持每行 <= 80 个字符。
不要使用 "sidebar" 注释,尤其是 if
子句(例如):
if (...) { // process the file
替换为:
// process the file
if (...) {
不要复制代码。当您复制类似的代码时 [如我用 filejoin
替换代码的地方],这表示编写模块化函数的好地方
无论如何,这是重构和修复的代码:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <assert.h>
#define FALSE 0
#define TRUE (! FALSE)
#define FIRST_TWO_FILES 2
#define FIRST_TWENTY_PRECENTS 1
#define MIDDLE_SIXTY_PRECENTS 2
#define LAST_TWENTY_PRECENTS 3
#define ALLOCME(_ptr,_len) \
do { \
_ptr = allocme(_ptr,_len,__FUNCTION__,__LINE__); \
} while (0)
#define FREEME(_ptr) \
do { \
if (_ptr != NULL) \
free(_ptr); \
_ptr = NULL; \
} while (0)
void
sysfault(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
vfprintf(stderr,fmt,ap);
va_end(ap);
exit(1);
}
long findLenOfFile(FILE * file);
char *readFile(FILE * f, char *dest, long len);
char menu(const char *scanFolder, const char *virusSignature);
char **writeFilesFromFolder(const char *scanFolder, char **filesList, int *len);
char *writePart(char *src, char *dest, int length, int *newLen, int part);
int findSignature(char *virusSignature, char *buffer, int sigLen,
int bufferLen);
void scanFiles(const char *scanFolder, char **filesList, int amountOfFiles,
char *virusSignature, long virusLength, char option);
int opt_fixme = 0;
// allocme -- guarded allocation
void *
allocme(void *ptr,size_t len,const char *fnc,int lno)
{
if (! opt_fixme) {
if (ptr != NULL)
sysfault("allocme: leaking ptr=%p len=%zu (from %s at line %d)\n",
ptr,len,fnc,lno);
}
ptr = realloc(ptr,len);
if (ptr == NULL)
sysfault("allocme: realloc failure\n");
return ptr;
}
#ifdef __linux__
const char *slash = "/";
#else
const char *slash = "\";
#endif
// filejoin -- create filename from directory and file tail
char *
filejoin(const char *dir,const char *tail)
{
size_t len;
char *file;
len = 0;
len += strlen(dir);
len += strlen(slash);
len += strlen(tail);
len += 1;
file = malloc(len);
if (file == NULL)
sysfault("filejoin: unable to alloc -- %s\n",strerror(errno));
*file = 0;
strcat(file,dir);
strcat(file,slash);
strcat(file,tail);
return file;
}
int
main(int argc, char **argv)
{
#if 0
char *log = malloc(strlen(argv[1]) + strlen("\Log.txt") + 4);
#else
char *log;
#endif
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'f':
opt_fixme = ! opt_fixme;
break;
}
}
if (argc != 2)
sysfault("usage: <folder_to_scan> <virus_signature_file>\n");
const char *topdir = argv[0];
const char *sigfile = argv[1];
FILE *virusSignatureFile = fopen(sigfile, "rb");
if (virusSignatureFile == NULL)
sysfault("main: unable to open '%s' -- %s\n",sigfile,strerror(errno));
long virusLength = 0;
#if 0
char **filesList = malloc(0);
#else
char **filesList = NULL;
#endif
char *virusSignature = NULL;
int amountOfFiles = 0;
char option = 0;
virusLength = findLenOfFile(virusSignatureFile);
// get the virusSignature as a string and write the files to check into the
// filesList
virusSignature = readFile(virusSignatureFile, virusSignature, virusLength);
#if 1
fclose(virusSignatureFile);
#endif
filesList = writeFilesFromFolder(topdir, filesList, &amountOfFiles);
// create log file
#if 0
strcpy(log, "");
strcat(log, argv[1]);
strcat(log, "\Log.txt");
#else
log = filejoin(topdir,"Log.txt");
#endif
FILE *logFile = fopen(log, "w");
fprintf(logFile, "Anti-virus began! Welcome!\n\n"
"Folder to scan:\n%s\n"
"Virus signature:\n%s\n\n"
"Scanning option:\n", topdir, sigfile);
// get scanning option (normal or quick) and continue accordingly
option = menu(topdir, sigfile);
if (option == '0') {
fprintf(logFile, "Normal Scan\n\n");
}
else {
fprintf(logFile, "Quick Scan\n\n");
}
fprintf(logFile, "Results:\n");
fclose(logFile);
// initiate scan
scanFiles(topdir, filesList, amountOfFiles, virusSignature, virusLength,
option);
#if 0
fclose(virusSignatureFile);
#endif
FREEME(log);
FREEME(filesList);
FREEME(virusSignature);
#ifndef __linux__
getchar();
#endif
return 0;
}
/*
This function will print the scanning folder path and signature path, also
will print the option menu to the user of quick or normal scan,
after that function will return user option(0, or other key)
input: scanFolder path (string), virus signature path (also string)
output: user option (char: '0', or other key)
*/
char
menu(const char *scanFolder, const char *virusSignature)
{
char userOption = '[=17=]';
printf("Welcome to my Virus Scan!\n\n"
"Folder to scan: %s\n"
"Virus signature: %s\n\n"
"Press 0 for a norman scan or any other key for a quick scan: ",
scanFolder, virusSignature);
userOption = getchar();
printf("Scanning began...\nThis process may take several minutes...\n\n");
return userOption;
}
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char **
writeFilesFromFolder(const char *scanFolder, char **filesList, int *len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = -FIRST_TWO_FILES;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (i >= 0) {
filesList = realloc(filesList,sizeof(*filesList) * (i + 1));
filesList[i] = strdup(dir->d_name);
}
i++;
}
closedir(d);
}
// first two names is "." and ".."
*len = i;
return filesList;
}
/*
This function will read the contents of a file into a string
input: a file (FILE *) to read from
output: char* with the contents of the file
*/
char *
readFile(FILE * f, char *dest, long len)
{
// NOTE/BUG: this does _not_ free the prior value -- memory leak!
ALLOCME(dest,len);
fread(dest, 1, len, f);
return dest;
}
void
scanFiles(const char *scanFolder, char **filesList, int amountOfFiles,
char *virusSignature, long virusLength, char option)
{
#if 0
char *log = malloc(strlen(scanFolder) + strlen("\Log.txt") + 1);
#else
char *log;
#endif
#if 0
char *buffer = malloc(0);
#else
char *buffer = NULL;
#endif
char *subBuffer = NULL;
long length = 0;
char *name = NULL;
int subLen = 0;
int i = 0;
FILE *f;
// reopen log file and append to it
#if 0
strcpy(log, "");
strcat(log, scanFolder);
strcat(log, "\Log.txt");
#else
log = filejoin(scanFolder,"Log.txt");
#endif
FILE *logFile = fopen(log, "a");
// iterate over each file
for (i = 0; i < amountOfFiles; i++) {
#if 0
name = malloc(strlen(scanFolder) + 1 + strlen(slash) + strlen(*(filesList + i)) + 20);
#endif
// open current file
#if 0
strcpy(name, "");
strcat(name, scanFolder);
strcat(name, slash);
strcat(name, *(filesList + i));
#else
name = filejoin(scanFolder,filesList[i]);
#endif
f = fopen(name, "rb");
length = findLenOfFile(f);
// if file can be accessed
if (f != NULL) {
buffer = readFile(f, buffer, length);
// Normal Mode
if (option == '0') {
if (findSignature(virusSignature, buffer, virusLength, length)) {
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - Clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
// Quick Mode
else {
// get first 20%
subBuffer = writePart(buffer, subBuffer, length, &subLen,
FIRST_TWENTY_PRECENTS);
if (findSignature(virusSignature, subBuffer, virusLength,
subLen)) {
printf("%s - infected! (first 20%%)\n", name);
fprintf(logFile, "%s - infected! (first 20%%)\n", name);
}
else {
FREEME(subBuffer);
// get last 20%
subBuffer = writePart(buffer, subBuffer, length, &subLen,
LAST_TWENTY_PRECENTS);
if (findSignature(virusSignature, subBuffer, virusLength,
subLen)) {
printf("%s - Infected! (last 20%%)\n", name);
fprintf(logFile, "%s - Infected! (last 20%%)\n", name);
}
else {
// get the 60% left in the middle
subBuffer = writePart(buffer, subBuffer, length,
&subLen, MIDDLE_SIXTY_PRECENTS);
if (findSignature(virusSignature, subBuffer,
virusLength, subLen)) {
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
}
FREEME(subBuffer);
}
fclose(f);
}
else {
printf("No file found\n");
}
FREEME(filesList[i]);
FREEME(name);
}
fclose(logFile);
FREEME(log);
FREEME(buffer);
getchar();
}
/*
This function will write part of the file (beginning, middle or end) to a string
input: source (string) to take the information from, destination (string) to
write a part of the source to it, length (int) of the source string, a pointer
(int*) to store the new length of the destination string and part of the file
to write from (int) 1,2 or 3: first 20%, 60% in the middle and last 20%
accordingly
output: string containing the desired part of the source string
*/
char *
writePart(char *src, char *dest, int length, int *newLen, int part)
{
int i = 0;
int percentedLength = 0;
int count = 0;
// this len is 20% of the entire file's length
percentedLength = (int) (length / 5);
// NOTE/BUG: this does _not_ free the prior value -- memory leak!
switch (part) {
case FIRST_TWENTY_PRECENTS: // return beginning
ALLOCME(dest,percentedLength);
*newLen = percentedLength;
for (i = 0; i < percentedLength; i++) {
*(dest + i) = *(src + i);
}
break;
case MIDDLE_SIXTY_PRECENTS: // return middle
// allocate space for the middle: The entire file size minus 20% from
// the start and 20% from the end
ALLOCME(dest,length - 2 * percentedLength);
*newLen = length - 2 * percentedLength;
for (i = percentedLength; i < length - percentedLength; i++) {
*(dest + count) = *(src + i);
count++;
}
break;
case LAST_TWENTY_PRECENTS: // return end
ALLOCME(dest,percentedLength);
*newLen = percentedLength;
for (i = length - percentedLength; i < length; i++) {
*(dest + count) = *(src + i);
count++;
}
break;
}
return dest;
}
/*
function that finds the length of a file
input: file (FILE *)
output: the file's length (long)
*/
long
findLenOfFile(FILE * file)
{
long length = 0;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
/*
function checks whether a file contains the virusSignature.
It iterates over each letter of the file and checks if it is the same as the
first letter in the virusSignature.
If it is, it checks the rest of the characters and returns True if a match is
found.
if not it continues the same process until the end of the file is reached.
input: The virusSignature (string), a buffer with the content of a file
(string), the signature's length (int)
and the buffer's length (int)
output: True if signature is in file, False otherwise
*/
int
findSignature(char *virusSignature, char *buffer, int sigLen, int bufferLen)
{
int found = 0;
int i = 0;
int j = 0;
for (i = 0; i < bufferLen - (sigLen - 1); i++) {
// check if a letter is the same as first letter in virusSignature
if (*(buffer + i) == *virusSignature)
{
found = TRUE;
// check if the rest of the letters match the signature and stop
// if one doesn't
for (j = 1; (j < sigLen) && found; j++) {
if (*(buffer + (i + j)) != *(virusSignature + j)) {
found = FALSE;
}
}
// if we got a match, return true!
if (found) {
return TRUE;
}
}
}
return FALSE;
}
在我发现某处有一段记忆 leak/error 之后,我已经坐了几个小时来检查这段代码 哪里漏了?如何修复? 这是 Dr.Memory 报告:
Dr. Memory version 2.3.0
Running "C:\Users\Beni\source\repos\Magshimim_EX8\Debug\Magshimim_EX8.exe"
Using system call file C:\Users\Beni\AppData\Roaming\Dr. Memory\symcache\syscalls_wow64.txt
Error #1: UNADDRESSABLE ACCESS: reading 1 byte(s)
replace_strlen
d:\drmemory_package\drmemory\replace.c(412):
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
Magshimim_EX8.exe!?
??:0
KERNEL32.dll!BaseThreadInitThunk
??:0
ERRORS FOUND:
1 unique, 1 total unaddressable access(es)
0 unique, 0 total uninitialized access(es)
0 unique, 0 total invalid heap argument(s)
0 unique, 0 total GDI usage error(s)
0 unique, 0 total handle leak(s)
0 unique, 0 total warning(s)
0 unique, 0 total, 0 byte(s) of leak(s)
0 unique, 0 total, 0 byte(s) of possible leak(s)
Details: C:\Users\Beni\AppData\Roaming\Dr. Memory\DrMemory-Magshimim_EX8.exe.5208.000\results.txt
WARNING: application exited with abnormal code 0xc0000005
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#define FALSE 0
#define TRUE !FALSE
#define FIRST_TWO_FILES 2
#define FIRST_TWENTY_PRECENTS 1
#define MIDDLE_SIXTY_PRECENTS 2
#define LAST_TWENTY_PRECENTS 3
long findLenOfFile(FILE * file);
char* readFile(FILE* f, char* dest, long len);
char menu(char* scanFolder, char* virusSignature);
char** writeFilesFromFolder(char* scanFolder, char ** filesList, int* len);
char* writePart(char* src, char* dest, int length, int* newLen, int part);
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen);
void scanFiles(char* scanFolder, char** filesList, int amountOfFiles, char* virusSignature, long virusLength, char option);
int main(int argc, char* argv[])
{
char* log = malloc(sizeof(char)*strlen(argv[1]) + sizeof(char)*strlen("\Log.txt") + 4);
FILE* virusSignatureFile = fopen(argv[2], "rb");
long virusLength = 0;
char** filesList = (char**)malloc(sizeof(char) * 0);
char* virusSignature = 0;
int amountOfFiles = 0;
char option = 0;
int i = 0;
virusLength = findLenOfFile(virusSignatureFile);
// get the virusSignature as a string and write the files to check into the filesList
virusSignature = readFile(virusSignatureFile, virusSignature, virusLength);
filesList = writeFilesFromFolder(argv[1], filesList, &amountOfFiles);
// create log file
strcpy(log, "");
strcat(log, argv[1]);
strcat(log, "\Log.txt");
FILE * logFile = fopen(log, "w");
fprintf(logFile, "Anti-virus began! Welcome!\n\nFolder to scan:\n%s\nVirus signature:\n%s\n\nScanning option:\n", argv[1], argv[2]);
// get scanning option (normal or quick) and continue accordingly
option = menu(argv[1], argv[2]);
if (option == '0') {
fprintf(logFile, "Normal Scan\n\n");
}
else {
fprintf(logFile, "Quick Scan\n\n");
}
fprintf(logFile, "Results:\n");
fclose(logFile);
// initiate scan
scanFiles(argv[1], filesList, amountOfFiles, virusSignature, virusLength, option);
fclose(virusSignatureFile);
free(log);
free(filesList);
free(virusSignature);
getchar();
return 0;
}
/*
This function will print the scanning folder path and signature path, also will print the option menu to the user of quick or normal scan,
after that function will return user option(0, or other key)
input: scanFolder path (string), virus signature path (also string)
output: user option (char: '0', or other key)
*/
char menu(char * scanFolder, char * virusSignature)
{
char userOption = '[=11=]';
printf("Welcome to my Virus Scan!\n\nFolder to scan: %s\nVirus signature: %s\n\nPress 0 for a norman scan or any other key for a quick scan: ", scanFolder, virusSignature);
userOption = getchar();
printf("Scanning began...\nThis process may take several minutes...\n\n");
return userOption;
}
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char** writeFilesFromFolder(char * scanFolder, char ** filesList, int* len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = 0;
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (i > 1)
{
filesList = (char**)realloc(filesList, sizeof(filesList) + sizeof(char*) + 4);
*(filesList + (i - FIRST_TWO_FILES)) = (char*)malloc(sizeof(char) * strlen(dir->d_name) + 1);
strcpy(*(filesList + (i - FIRST_TWO_FILES)), (dir->d_name));
}
i++;
}
closedir(d);
}
*len = i - FIRST_TWO_FILES; //first two names is "." and ".."
return filesList;
}
/*
This function will read the contents of a file into a string
input: a file (FILE *) to read from
output: char* with the contents of the file
*/
char* readFile(FILE* f, char * dest, long len)
{
dest = (char*)malloc(sizeof(char) * len);
fread(dest, 1, len, f);
return dest;
}
void scanFiles(char * scanFolder, char ** filesList, int amountOfFiles, char * virusSignature, long virusLength, char option)
{
char* log = malloc(sizeof(char)*strlen(scanFolder) + sizeof(char)*strlen("\Log.txt") + 1);
char * buffer = (char*)malloc(sizeof(char) * 0);
char* subBuffer = 0;
char* slash = "\";
long length = 0;
char* name = 0;
int subLen = 0;
int i = 0;
FILE * f;
// reopen log file and append to it
strcpy(log, "");
strcat(log, scanFolder);
strcat(log, "\Log.txt");
FILE * logFile = fopen(log, "a");
// iterate over each file
for (i = 0; i < amountOfFiles; i++)
{
name = (char*)malloc(sizeof(char) * strlen(scanFolder) + 1 + sizeof(char) * strlen(slash) + sizeof(char) * strlen(*(filesList + i)) + 20);
// open current file
strcpy(name, "");
strcat(name, scanFolder);
strcat(name, slash);
strcat(name, *(filesList + i));
f = fopen(name, "rb");
length = findLenOfFile(f);
if (f != NULL) // if file can be accessed
{
buffer = readFile(f, buffer, length);
if (option == '0') { // Normal Mode
if (findSignature(virusSignature, buffer, virusLength, length))
{
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else
{
printf("%s - Clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
else { // Quick Mode
subBuffer = writePart(buffer, subBuffer, length, &subLen, FIRST_TWENTY_PRECENTS); // get first 20%
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - infected! (first 20%%)\n", name);
fprintf(logFile, "%s - infected! (first 20%%)\n", name);
}
else {
free(subBuffer);
subBuffer = writePart(buffer, subBuffer, length, &subLen, LAST_TWENTY_PRECENTS); // get last 20%
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - Infected! (last 20%%)\n", name);
fprintf(logFile, "%s - Infected! (last 20%%)\n", name);
}
else {
subBuffer = writePart(buffer, subBuffer, length, &subLen, MIDDLE_SIXTY_PRECENTS); // get the 60% left in the middle
if (findSignature(virusSignature, subBuffer, virusLength, subLen))
{
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
}
free(subBuffer);
}
fclose(f);
}
else
{
printf("No file found\n");
}
free(*(filesList + i));
free(name);
}
fclose(logFile);
free(log);
free(buffer);
getchar();
}
/*
This function will write part of the file (beginning, middle or end) to a string
input: source (string) to take the information from, destination (string) to write a part of the source to it,
length (int) of the source string, a pointer (int*) to store the new length of the destination string and
part of the file to write from (int) 1,2 or 3: first 20%, 60% in the middle and last 20% accordingly
output: string containing the desired part of the source string
*/
char* writePart(char *src, char *dest, int length, int *newLen, int part) {
int i = 0;
int percentedLength = 0;
int count = 0;
percentedLength = (int)(length / 5); // this len is 20% of the entire file's length
if (part == FIRST_TWENTY_PRECENTS) // return beginning
{
dest = (char*)malloc(sizeof(char) * percentedLength);
*newLen = percentedLength;
for (i = 0; i < percentedLength; i++)
{
*(dest + i) = *(src + i);
}
}
else if (part == MIDDLE_SIXTY_PRECENTS) // return middle
{
// allocate space for the middle: The entire file size minus 20% from the start and 20% from the end
dest = (char*)malloc(sizeof(char) * (length - 2 * percentedLength));
*newLen = length - 2 * percentedLength;
for (i = percentedLength; i < length - percentedLength; i++) {
*(dest + count) = *(src + i);
count++;
}
}
else if (part == LAST_TWENTY_PRECENTS) // return end
{
dest = (char*)malloc(sizeof(char) * percentedLength);
*newLen = percentedLength;
for (i = length - percentedLength; i < length; i++)
{
*(dest + count) = *(src + i);
count++;
}
}
return dest;
}
/*
function that finds the length of a file
input: file (FILE *)
output: the file's length (long)
*/
long findLenOfFile(FILE * file)
{
long length = 0;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
/*
function checks whether a file contains the virusSignature. It iterates over each letter of the file and checks
if it is the same as the first letter in the virusSignature. If it is, it checks the rest of the characters and
returns True if a match is found. if not it continues the same process until the end of the file is reached.
input: The virusSignature (string), a buffer with the content of a file (string), the signature's length (int)
and the buffer's length (int)
output: True if signature is in file, False otherwise
*/
int findSignature(char* virusSignature, char* buffer, int sigLen, int bufferLen)
{
int found = 0;
int i = 0;
int j = 0;
for (i = 0; i < bufferLen - (sigLen - 1); i++) {
if (*(buffer + i) == *virusSignature) // check if a letter is the same as first letter in virusSignature
{
found = TRUE;
// check if the rest of the letters match the signature and stop if one doesn't
for (j = 1; (j < sigLen) && found; j++) {
if (*(buffer + (i + j)) != *(virusSignature + j)) {
found = FALSE;
}
}
if (found) {
return TRUE; // if we got a match, return true!
}
}
}
return FALSE;
}
writeFilesFromFolder
中的 realloc
调用有错误。
是:
filesList = (char **) realloc(filesList, sizeof(filesList) + sizeof(char *) + 4);
请注意分配给 filesList
的 space 是 常量 。随着新元素的添加,它不会增长,因此您有未定义的行为。
这不是工具检测到的内存泄漏。内存泄漏意味着您无法 free
超出范围的指针。
相反,您存储的数据超出了您分配的区域的末尾,破坏了那里的所有内容,这可能是 malloc
等的 [隐藏] 链指针区域。阿尔。用于跟踪分配。
我不确定 sizeof
中的任何一个因素,但是,filesList
是一个指针,所以 sizeof(filesList)
是常量 [在 32 位机器上为 4 或者8 表示 64 位。
分配的space必须按比例增加到i
。
这是该函数的重构版本,它修复了错误并进行了一些简化和清理:
顺便说一句,不要投malloc
:Do I cast the result of malloc?
此外,请注意 sizeof(char)
[根据定义] 始终 1,无论 char
对于给定架构实际具有多少位。因此,删除任何 sizeof(char) *
而不是(例如):
*(filesList + i)
通常simpler/cleaner要做:
filesList[i]
无论如何,这是代码:
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char **
writeFilesFromFolder(char *scanFolder, char **filesList, int *len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = -FIRST_TWO_FILES;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (i >= 0) {
filesList = realloc(filesList,sizeof(*filesList) * (i + 1));
filesList[i] = strdup(dir->d_name);
}
i++;
}
closedir(d);
}
*len = i; // first two names is "." and ".."
return filesList;
}
更新:
好的,你确实有内存泄漏。而且,我编写了检测和修复程序。
首先,您所做的是将缓冲区指针作为参数(例如dest
)传递给函数(例如readFile
或writePart
)。
那么,你在做:
dest = malloc(percentedLength);
这个 泄漏 dest
的 以前的 值。
通常,分配缓冲区的函数 return 它 而不是 将其作为参数。但是,在分析您的代码后,将 malloc
替换为 realloc
可以防止泄漏。
我必须进行完整的代码审查才能找到它。而且,我在此过程中进行了几次简化和清理,以尝试理解您的代码并隔离可能的进一步问题。
我用新函数 filejoin
替换了你的 allocation/concatenation 个文件名。
我用宏替换了其他 malloc
调用:ALLOCME
检测内存泄漏 在 发生之前。这与替换 free
调用的 [new] FREEME
宏结合使用。
默认模式是检测泄漏并中止。如果你给程序一个 -f
选项,它会解决这个问题。在你分析明白发生了什么之后,你可以把默认的改为"fix"模式。
在可能的情况下,我将您的原始代码留在 #if 0
更多风格提示:
保持每行 <= 80 个字符。
不要使用 "sidebar" 注释,尤其是 if
子句(例如):
if (...) { // process the file
替换为:
// process the file
if (...) {
不要复制代码。当您复制类似的代码时 [如我用 filejoin
替换代码的地方],这表示编写模块化函数的好地方
无论如何,这是重构和修复的代码:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <assert.h>
#define FALSE 0
#define TRUE (! FALSE)
#define FIRST_TWO_FILES 2
#define FIRST_TWENTY_PRECENTS 1
#define MIDDLE_SIXTY_PRECENTS 2
#define LAST_TWENTY_PRECENTS 3
#define ALLOCME(_ptr,_len) \
do { \
_ptr = allocme(_ptr,_len,__FUNCTION__,__LINE__); \
} while (0)
#define FREEME(_ptr) \
do { \
if (_ptr != NULL) \
free(_ptr); \
_ptr = NULL; \
} while (0)
void
sysfault(const char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
vfprintf(stderr,fmt,ap);
va_end(ap);
exit(1);
}
long findLenOfFile(FILE * file);
char *readFile(FILE * f, char *dest, long len);
char menu(const char *scanFolder, const char *virusSignature);
char **writeFilesFromFolder(const char *scanFolder, char **filesList, int *len);
char *writePart(char *src, char *dest, int length, int *newLen, int part);
int findSignature(char *virusSignature, char *buffer, int sigLen,
int bufferLen);
void scanFiles(const char *scanFolder, char **filesList, int amountOfFiles,
char *virusSignature, long virusLength, char option);
int opt_fixme = 0;
// allocme -- guarded allocation
void *
allocme(void *ptr,size_t len,const char *fnc,int lno)
{
if (! opt_fixme) {
if (ptr != NULL)
sysfault("allocme: leaking ptr=%p len=%zu (from %s at line %d)\n",
ptr,len,fnc,lno);
}
ptr = realloc(ptr,len);
if (ptr == NULL)
sysfault("allocme: realloc failure\n");
return ptr;
}
#ifdef __linux__
const char *slash = "/";
#else
const char *slash = "\";
#endif
// filejoin -- create filename from directory and file tail
char *
filejoin(const char *dir,const char *tail)
{
size_t len;
char *file;
len = 0;
len += strlen(dir);
len += strlen(slash);
len += strlen(tail);
len += 1;
file = malloc(len);
if (file == NULL)
sysfault("filejoin: unable to alloc -- %s\n",strerror(errno));
*file = 0;
strcat(file,dir);
strcat(file,slash);
strcat(file,tail);
return file;
}
int
main(int argc, char **argv)
{
#if 0
char *log = malloc(strlen(argv[1]) + strlen("\Log.txt") + 4);
#else
char *log;
#endif
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'f':
opt_fixme = ! opt_fixme;
break;
}
}
if (argc != 2)
sysfault("usage: <folder_to_scan> <virus_signature_file>\n");
const char *topdir = argv[0];
const char *sigfile = argv[1];
FILE *virusSignatureFile = fopen(sigfile, "rb");
if (virusSignatureFile == NULL)
sysfault("main: unable to open '%s' -- %s\n",sigfile,strerror(errno));
long virusLength = 0;
#if 0
char **filesList = malloc(0);
#else
char **filesList = NULL;
#endif
char *virusSignature = NULL;
int amountOfFiles = 0;
char option = 0;
virusLength = findLenOfFile(virusSignatureFile);
// get the virusSignature as a string and write the files to check into the
// filesList
virusSignature = readFile(virusSignatureFile, virusSignature, virusLength);
#if 1
fclose(virusSignatureFile);
#endif
filesList = writeFilesFromFolder(topdir, filesList, &amountOfFiles);
// create log file
#if 0
strcpy(log, "");
strcat(log, argv[1]);
strcat(log, "\Log.txt");
#else
log = filejoin(topdir,"Log.txt");
#endif
FILE *logFile = fopen(log, "w");
fprintf(logFile, "Anti-virus began! Welcome!\n\n"
"Folder to scan:\n%s\n"
"Virus signature:\n%s\n\n"
"Scanning option:\n", topdir, sigfile);
// get scanning option (normal or quick) and continue accordingly
option = menu(topdir, sigfile);
if (option == '0') {
fprintf(logFile, "Normal Scan\n\n");
}
else {
fprintf(logFile, "Quick Scan\n\n");
}
fprintf(logFile, "Results:\n");
fclose(logFile);
// initiate scan
scanFiles(topdir, filesList, amountOfFiles, virusSignature, virusLength,
option);
#if 0
fclose(virusSignatureFile);
#endif
FREEME(log);
FREEME(filesList);
FREEME(virusSignature);
#ifndef __linux__
getchar();
#endif
return 0;
}
/*
This function will print the scanning folder path and signature path, also
will print the option menu to the user of quick or normal scan,
after that function will return user option(0, or other key)
input: scanFolder path (string), virus signature path (also string)
output: user option (char: '0', or other key)
*/
char
menu(const char *scanFolder, const char *virusSignature)
{
char userOption = '[=17=]';
printf("Welcome to my Virus Scan!\n\n"
"Folder to scan: %s\n"
"Virus signature: %s\n\n"
"Press 0 for a norman scan or any other key for a quick scan: ",
scanFolder, virusSignature);
userOption = getchar();
printf("Scanning began...\nThis process may take several minutes...\n\n");
return userOption;
}
/*
This function writes all files name from folder to the filesList
input: the scanning folder path
output: amount of files
*/
char **
writeFilesFromFolder(const char *scanFolder, char **filesList, int *len)
{
DIR *d = 0;
struct dirent *dir;
d = opendir(scanFolder);
int i = -FIRST_TWO_FILES;
if (d) {
while ((dir = readdir(d)) != NULL) {
if (i >= 0) {
filesList = realloc(filesList,sizeof(*filesList) * (i + 1));
filesList[i] = strdup(dir->d_name);
}
i++;
}
closedir(d);
}
// first two names is "." and ".."
*len = i;
return filesList;
}
/*
This function will read the contents of a file into a string
input: a file (FILE *) to read from
output: char* with the contents of the file
*/
char *
readFile(FILE * f, char *dest, long len)
{
// NOTE/BUG: this does _not_ free the prior value -- memory leak!
ALLOCME(dest,len);
fread(dest, 1, len, f);
return dest;
}
void
scanFiles(const char *scanFolder, char **filesList, int amountOfFiles,
char *virusSignature, long virusLength, char option)
{
#if 0
char *log = malloc(strlen(scanFolder) + strlen("\Log.txt") + 1);
#else
char *log;
#endif
#if 0
char *buffer = malloc(0);
#else
char *buffer = NULL;
#endif
char *subBuffer = NULL;
long length = 0;
char *name = NULL;
int subLen = 0;
int i = 0;
FILE *f;
// reopen log file and append to it
#if 0
strcpy(log, "");
strcat(log, scanFolder);
strcat(log, "\Log.txt");
#else
log = filejoin(scanFolder,"Log.txt");
#endif
FILE *logFile = fopen(log, "a");
// iterate over each file
for (i = 0; i < amountOfFiles; i++) {
#if 0
name = malloc(strlen(scanFolder) + 1 + strlen(slash) + strlen(*(filesList + i)) + 20);
#endif
// open current file
#if 0
strcpy(name, "");
strcat(name, scanFolder);
strcat(name, slash);
strcat(name, *(filesList + i));
#else
name = filejoin(scanFolder,filesList[i]);
#endif
f = fopen(name, "rb");
length = findLenOfFile(f);
// if file can be accessed
if (f != NULL) {
buffer = readFile(f, buffer, length);
// Normal Mode
if (option == '0') {
if (findSignature(virusSignature, buffer, virusLength, length)) {
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - Clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
// Quick Mode
else {
// get first 20%
subBuffer = writePart(buffer, subBuffer, length, &subLen,
FIRST_TWENTY_PRECENTS);
if (findSignature(virusSignature, subBuffer, virusLength,
subLen)) {
printf("%s - infected! (first 20%%)\n", name);
fprintf(logFile, "%s - infected! (first 20%%)\n", name);
}
else {
FREEME(subBuffer);
// get last 20%
subBuffer = writePart(buffer, subBuffer, length, &subLen,
LAST_TWENTY_PRECENTS);
if (findSignature(virusSignature, subBuffer, virusLength,
subLen)) {
printf("%s - Infected! (last 20%%)\n", name);
fprintf(logFile, "%s - Infected! (last 20%%)\n", name);
}
else {
// get the 60% left in the middle
subBuffer = writePart(buffer, subBuffer, length,
&subLen, MIDDLE_SIXTY_PRECENTS);
if (findSignature(virusSignature, subBuffer,
virusLength, subLen)) {
printf("%s - Infected!\n", name);
fprintf(logFile, "%s - Infected!\n", name);
}
else {
printf("%s - clean\n", name);
fprintf(logFile, "%s - Clean\n", name);
}
}
}
FREEME(subBuffer);
}
fclose(f);
}
else {
printf("No file found\n");
}
FREEME(filesList[i]);
FREEME(name);
}
fclose(logFile);
FREEME(log);
FREEME(buffer);
getchar();
}
/*
This function will write part of the file (beginning, middle or end) to a string
input: source (string) to take the information from, destination (string) to
write a part of the source to it, length (int) of the source string, a pointer
(int*) to store the new length of the destination string and part of the file
to write from (int) 1,2 or 3: first 20%, 60% in the middle and last 20%
accordingly
output: string containing the desired part of the source string
*/
char *
writePart(char *src, char *dest, int length, int *newLen, int part)
{
int i = 0;
int percentedLength = 0;
int count = 0;
// this len is 20% of the entire file's length
percentedLength = (int) (length / 5);
// NOTE/BUG: this does _not_ free the prior value -- memory leak!
switch (part) {
case FIRST_TWENTY_PRECENTS: // return beginning
ALLOCME(dest,percentedLength);
*newLen = percentedLength;
for (i = 0; i < percentedLength; i++) {
*(dest + i) = *(src + i);
}
break;
case MIDDLE_SIXTY_PRECENTS: // return middle
// allocate space for the middle: The entire file size minus 20% from
// the start and 20% from the end
ALLOCME(dest,length - 2 * percentedLength);
*newLen = length - 2 * percentedLength;
for (i = percentedLength; i < length - percentedLength; i++) {
*(dest + count) = *(src + i);
count++;
}
break;
case LAST_TWENTY_PRECENTS: // return end
ALLOCME(dest,percentedLength);
*newLen = percentedLength;
for (i = length - percentedLength; i < length; i++) {
*(dest + count) = *(src + i);
count++;
}
break;
}
return dest;
}
/*
function that finds the length of a file
input: file (FILE *)
output: the file's length (long)
*/
long
findLenOfFile(FILE * file)
{
long length = 0;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
/*
function checks whether a file contains the virusSignature.
It iterates over each letter of the file and checks if it is the same as the
first letter in the virusSignature.
If it is, it checks the rest of the characters and returns True if a match is
found.
if not it continues the same process until the end of the file is reached.
input: The virusSignature (string), a buffer with the content of a file
(string), the signature's length (int)
and the buffer's length (int)
output: True if signature is in file, False otherwise
*/
int
findSignature(char *virusSignature, char *buffer, int sigLen, int bufferLen)
{
int found = 0;
int i = 0;
int j = 0;
for (i = 0; i < bufferLen - (sigLen - 1); i++) {
// check if a letter is the same as first letter in virusSignature
if (*(buffer + i) == *virusSignature)
{
found = TRUE;
// check if the rest of the letters match the signature and stop
// if one doesn't
for (j = 1; (j < sigLen) && found; j++) {
if (*(buffer + (i + j)) != *(virusSignature + j)) {
found = FALSE;
}
}
// if we got a match, return true!
if (found) {
return TRUE;
}
}
}
return FALSE;
}