src/filegen.c: improve Frama-C annotations

This commit is contained in:
Christophe Grenier 2023-10-08 14:00:23 +02:00
parent b05dfc200b
commit 0fdbc68915
2 changed files with 112 additions and 54 deletions

View file

@ -348,16 +348,21 @@ void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode)
/*@ assert valid_file_check_result(file_recovery); */
return;
}
/*@ assert valid_file_recovery(file_recovery); */
taille=fread(buffer,1, 4096,file_recovery->handle);
/*@ assert valid_file_recovery(file_recovery); */
#ifdef __FRAMAC__
Frama_C_make_unknown(&buffer, 4096);
#endif
/*@ assert valid_file_recovery(file_recovery); */
/*@ assert file_recovery->file_size < 0x8000000000000000-2; */
if(taille > 0 && buffer[0]=='\n' && (nl_mode&NL_BARENL)==NL_BARENL)
file_recovery->file_size++;
else if(taille > 1 && buffer[0]=='\r' && buffer[1]=='\n' && (nl_mode&NL_CRLF)==NL_CRLF)
file_recovery->file_size+=2;
else if(taille > 0 && buffer[0]=='\r' && (nl_mode&NL_BARECR)==NL_BARECR)
file_recovery->file_size++;
/*@ assert file_recovery->file_size < 0x8000000000000000; */
/*@ assert \valid(file_recovery->handle); */
/*@ assert valid_file_recovery(file_recovery); */
/*@ assert valid_file_check_result(file_recovery); */
@ -376,7 +381,7 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
memset(&buffer[4096],0,footer_length-1);
/*@
@ loop invariant 0 <= offset <= \at(offset, Pre);
@ loop invariant offset <= PHOTOREC_MAX_FILE_SIZE;
@ loop invariant offset < 0x8000000000000000;
@ loop assigns errno, *handle, Frama_C_entropy_source;
@ loop assigns offset, buffer[0 .. 8192-1];
@ loop variant offset;
@ -391,7 +396,7 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
offset-=4096;
else
offset=offset-(offset%4096);
/*@ assert offset + 4096 <= PHOTOREC_MAX_FILE_SIZE; */
/*@ assert offset + 4096 <= 0x8000000000000000; */
if(my_fseek(handle,offset,SEEK_SET)<0)
return 0;
taille=fread(&buffer, 1, 4096, handle);
@ -407,7 +412,7 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
@*/
for(i=taille-1;i>=0;i--)
{
/*@ assert offset + i <= PHOTOREC_MAX_FILE_SIZE; */
/*@ assert offset + i <= 0x8000000000000000; */
if(buffer[i]==*(const char *)footer && memcmp(&buffer[i],footer,footer_length)==0)
{
return offset + i;
@ -540,42 +545,62 @@ file_stat_t * init_file_stats(file_enable_t *files_enable)
/*@
@ requires \valid(file_recovery);
@ requires valid_file_recovery(file_recovery);
@ requires strlen(&file_recovery->filename[0]) > 0;
@ requires valid_read_string(new_ext);
@ requires separation: \separated(file_recovery, new_ext);
@ ensures valid_file_recovery(file_recovery);
@*/
static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext)
{
#ifndef DISABLED_FOR_FRAMAC
/*@ assert valid_string((char *)&file_recovery->filename); */
char new_filename[sizeof(file_recovery->filename)];
char *dst;
char *dst_dir_sep;
unsigned int len=strlen(file_recovery->filename)+1;
len+=strlen(new_ext);
const unsigned int len=strlen(file_recovery->filename)+1+strlen(new_ext)+1;
/*@ assert valid_read_string(&file_recovery->filename[0]); */
if(len > sizeof(file_recovery->filename))
{
/*@ assert valid_read_string((const char *)&file_recovery->filename); */
/*@ assert valid_string((char *)&file_recovery->filename); */
return -1;
}
/*@ assert len <= sizeof(file_recovery->filename); */
/*@ assert valid_read_string((char*)&file_recovery->filename); */
strcpy(new_filename, (char *)&file_recovery->filename);
/*@ assert valid_string((char *)&new_filename); */
/*@ assert \initialized((char *)&file_recovery->filename +(0..strlen(&file_recovery->filename[0]))); */
memcpy(new_filename, (char *)&file_recovery->filename, sizeof(file_recovery->filename));
/*@ assert valid_string(&new_filename[0]); */
/*@ assert \initialized((char *)&new_filename[0] +(0..strlen(&new_filename[0]))); */
#ifdef DISABLED_FOR_FRAMAC
dst_dir_sep=new_filename;
#else
dst_dir_sep=strrchr(new_filename, '/');
/*@ assert dst_dir_sep==\null || valid_string(dst_dir_sep); */
/*@ assert dst_dir_sep==\null || \subset(dst_dir_sep, &new_filename[0] +(0..strlen(&new_filename[0]))); */
/*@ assert dst_dir_sep==\null || \initialized(dst_dir_sep +(0..strlen(dst_dir_sep))); */
if(dst_dir_sep==NULL)
dst_dir_sep=new_filename;
#endif
/*@ assert valid_string(dst_dir_sep); */
/*@ assert \initialized((char *)dst_dir_sep +(0..strlen(dst_dir_sep))); */
dst=dst_dir_sep;
/*@ assert valid_string(dst); */
/*@ assert \initialized(dst); */
/*@ ghost char *odst = dst; */
/*@
@ loop invariant valid_string(dst);
@ loop invariant \initialized(dst);
@ loop invariant odst <= dst <= odst + strlen(odst);
@ loop assigns dst;
@ loop variant strlen(dst);
@*/
while(*dst!='.' && *dst!='\0')
dst++;
/* Add extension */
{
const char *src;
src=new_ext;
*dst++ = '.';
while(*src!='\0')
*dst++ = *src++;
*dst='\0';
}
#ifdef DISABLED_FOR_FRAMAC
memcpy(dst, new_ext, strlen(new_ext)+1);
#else
strcpy(dst, new_ext);
#endif
/*@ assert valid_string(&new_filename[0]); */
if(strlen(new_filename) >= sizeof(file_recovery->filename))
{
@ -589,33 +614,30 @@ static int file_rename_aux(file_recovery_t *file_recovery, const char *new_ext)
/*@ assert valid_read_string((const char *)&file_recovery->filename); */
return -1;
}
/*@ assert valid_file_recovery(file_recovery); */
/*@ assert valid_read_string(&new_filename[0]); */
strcpy(file_recovery->filename, new_filename);
#else
file_recovery->filename[0]='/';
file_recovery->filename[1]='\0';
#endif
memcpy(file_recovery->filename, new_filename, sizeof(file_recovery->filename));
/*@ assert valid_read_string((const char *)&file_recovery->filename); */
/*@ assert valid_file_recovery(file_recovery); */
return 0;
}
/*@
@ requires \valid(file_recovery);
@ requires strlen((char*)&file_recovery->filename) < 1<<30;
@ requires valid_file_recovery(file_recovery);
@ requires valid_read_string((char*)&file_recovery->filename);
@ requires valid_string(filename);
@ requires \valid(filename +(0..2047));
@ requires 0 < strlen(filename) < 1<<30;
@ requires 0 <= offset < buffer_size;
@ requires buffer_size < 1<<30;
@ requires \valid_read((char *)buffer+(0..buffer_size-1));
@ requires new_ext==\null || (valid_read_string(new_ext) && strlen(new_ext) < 1<<30);
@ ensures new_ext==\null || (valid_read_string(new_ext) && strlen(new_ext) < 1<<30);
@ ensures valid_file_recovery(file_recovery);
@ ensures valid_string(filename);
@ ensures 0 < strlen(filename) < 1<<30;
@*/
static int _file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
static int _file_rename(char *filename, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
char *new_filename;
const char *src=file_recovery->filename;
const char *src=filename;
const char *ext=NULL;
char *dst;
char *directory_sep;
@ -624,11 +646,25 @@ static int _file_rename(file_recovery_t *file_recovery, const void *buffer, cons
/*@ assert offset < buffer_size; */
len+=buffer_size-offset+1;
if(new_ext!=NULL)
len+=strlen(new_ext);
len+=strlen(new_ext)+1;
#ifndef DISABLED_FOR_FRAMAC
new_filename=(char*)MALLOC(len);
dst=new_filename;
directory_sep=new_filename;
directory_sep=dst;
strcpy(dst, src);
/*@ ghost char *osrc = src; */
/*@ ghost char *odst = dst; */
/*@ assert valid_read_string(osrc); */
//X loop assigns src, dst, odst[0..strlen(osrc)];
//X loop assigns directory_sep, ext;
/*@ loop invariant osrc <= src <= osrc + strlen(osrc);
loop invariant odst <= dst <= odst + strlen(osrc);
loop invariant valid_read_string(src);
loop invariant dst - odst == src - osrc;
loop invariant strlen(src) == strlen(osrc) - (src - osrc);
loop invariant \forall integer i; 0 <= i < src - osrc ==> odst[i] == osrc[i];
loop variant strlen(osrc) - (src - osrc);
*/
while(*src!='\0')
{
if(*src=='/')
@ -641,20 +677,31 @@ static int _file_rename(file_recovery_t *file_recovery, const void *buffer, cons
*dst++ = *src++;
}
*dst='\0';
//@ assert *dst == '\0' && *src == '\0';
//@ assert valid_string(odst);
dst=directory_sep;
/*@
@ loop invariant valid_string(dst);
@ loop assigns dst;
@*/
while(*dst!='.' && *dst!='\0')
dst++;
/* Add original filename */
{
char *dst_old=dst;
/*@ assert valid_string(dst_old); */
int off;
int ok=0;
int bad=0;
*dst++ = '_';
src=&((const char *)buffer)[offset];
for(off=offset; off<buffer_size && *src!='\0'; off++, src++)
/*@
@ loop invariant offset <= off <= buffer_size;
@ loop invariant valid_read_string(src);
@*/
for(off=offset; off<buffer_size && *src!='\0'; off++)
{
switch(*src)
const char c=((const char *)buffer)[off];
switch(c)
{
case '/':
case '\\':
@ -669,9 +716,9 @@ static int _file_rename(file_recovery_t *file_recovery, const void *buffer, cons
bad++;
break;
default:
if(isprint(*src) && !isspace(*src) && !ispunct(*src) && !iscntrl(*src))
if(isprint(c) && !isspace(c) && !ispunct(c) && !iscntrl(c))
{
*dst++ = *src;
*dst++ = c;
ok++;
}
else
@ -687,6 +734,10 @@ static int _file_rename(file_recovery_t *file_recovery, const void *buffer, cons
dst=dst_old;
else
{
/*@
@ loop invariant dst_old <= dst;
@ loop assigns dst;
@*/
while(dst > dst_old && *(dst-1)=='_')
dst--;
}
@ -694,46 +745,43 @@ static int _file_rename(file_recovery_t *file_recovery, const void *buffer, cons
/* Add extension */
if(new_ext!=NULL)
{
src=new_ext;
*dst++ = '.';
while(*src!='\0')
*dst++ = *src++;
strcpy(dst, new_ext);
}
else if(append_original_ext>0)
{
if(ext!=NULL)
{
while(*ext!='\0')
*dst++ = *ext++;
strcpy(dst, ext);
}
}
*dst='\0';
/*@ assert valid_read_string(new_filename); */
/*@ assert valid_read_string(&file_recovery->filename[0]); */
if(strlen(new_filename)<sizeof(file_recovery->filename) && rename(file_recovery->filename, new_filename)==0)
/*@ assert valid_string(filename); */
if(strlen(new_filename)<2048 && rename(filename, new_filename)==0)
{
strcpy(file_recovery->filename, new_filename);
strcpy(filename, new_filename);
free(new_filename);
/*@ assert valid_read_string(&file_recovery->filename[0]); */
/*@ assert valid_file_recovery(file_recovery); */
/*@ assert valid_string(filename); */
return 0;
}
free(new_filename);
#endif
/*@ assert valid_read_string(&file_recovery->filename[0]); */
/*@ assert valid_file_recovery(file_recovery); */
/*@ assert valid_string(filename); */
return -1;
}
/* The original filename begins at offset in buffer and is null terminated */
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int append_original_ext)
{
if(file_recovery->filename[0] == 0)
return 0;
/*@ assert strlen((char *)&file_recovery->filename) > 0; */
/*@ assert new_ext==\null || valid_read_string(new_ext); */
if(buffer!=NULL && 0 <= offset && offset < buffer_size &&
_file_rename(file_recovery, buffer, buffer_size, offset, new_ext, append_original_ext)==0)
_file_rename(file_recovery->filename, buffer, buffer_size, offset, new_ext, append_original_ext)==0)
return 0;
/*@ assert valid_read_string((char const *)(&file_recovery->filename)); */
/*@ assert valid_string((char *)(&file_recovery->filename)); */
/*@ assert new_ext==\null || valid_read_string(new_ext); */
if(new_ext==NULL)
return 0;

View file

@ -39,6 +39,8 @@ extern "C" {
#define PHOTOREC_MAX_SIZE_32 (((uint64_t)1<<31)-1)
#define PHOTOREC_MAX_SIG_OFFSET 65535
#define PHOTOREC_MAX_SIG_SIZE 4095
/* TODO: Support blocksize up to 32 MB */
#define PHOTOREC_MAX_BLOCKSIZE 32*1024*1024
typedef enum { DC_SCAN=0, DC_CONTINUE=1, DC_STOP=2, DC_ERROR=3} data_check_t;
typedef struct file_hint_struct file_hint_t;
@ -144,6 +146,7 @@ typedef struct
predicate valid_file_stat(file_stat_t *file_stat) = (\valid_read(file_stat) && valid_file_hint(file_stat->file_hint));
predicate valid_file_recovery(file_recovery_t *file_recovery) = (\valid_read(file_recovery) &&
strlen((const char*)file_recovery->filename) < 1<<30 &&
valid_read_string((const char *)file_recovery->filename) &&
(file_recovery->file_stat == \null || valid_file_stat(file_recovery->file_stat)) &&
(file_recovery->handle == \null || \valid(file_recovery->handle)) &&
@ -195,11 +198,13 @@ typedef struct
predicate valid_data_check_param(unsigned char *buffer, unsigned int buffer_size, file_recovery_t *file_recovery) = (
buffer_size > 0 &&
(buffer_size&1)==0 &&
buffer_size <= 2 * PHOTOREC_MAX_BLOCKSIZE &&
\valid_read(buffer+(0..buffer_size-1)) &&
\initialized(buffer+(0..buffer_size-1)) &&
\valid(file_recovery) &&
valid_file_recovery(file_recovery) &&
file_recovery->calculated_file_size <= PHOTOREC_MAX_FILE_SIZE &&
file_recovery->file_size <= PHOTOREC_MAX_FILE_SIZE &&
\separated(buffer + (..), file_recovery)
);
@ -238,9 +243,11 @@ void file_allow_nl(file_recovery_t *file_recovery, const unsigned int nl_mode);
/*@
@ requires \valid(handle);
@ requires offset < 0x8000000000000000;
@ requires 0 < footer_length <4096;
@ requires \valid_read((char *)footer+(0..footer_length-1));
@ requires \separated(handle, (char *)footer + (..), &errno, &Frama_C_entropy_source);
@ ensures \result < 0x8000000000000000;
@ assigns *handle, errno, Frama_C_entropy_source;
@*/
uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const unsigned int footer_length);
@ -250,6 +257,8 @@ uint64_t file_rsearch(FILE *handle, uint64_t offset, const void*footer, const un
@ requires \valid_read((char *)footer+(0..footer_length-1));
@ requires \separated(file_recovery, file_recovery->handle, file_recovery->extension, &errno, &Frama_C_entropy_source);
@ requires valid_file_check_param(file_recovery);
@ requires extra_length <= PHOTOREC_MAX_FILE_SIZE;
@ requires file_recovery->file_size < 0x8000000000000000;
@ ensures valid_file_check_result(file_recovery);
@ assigns *file_recovery->handle, errno, file_recovery->file_size;
@ assigns Frama_C_entropy_source;
@ -356,23 +365,24 @@ void register_header_check(const unsigned int offset, const void *value, const u
/*@
@ requires \valid(files_enable);
@ decreases 0;
@*/
file_stat_t * init_file_stats(file_enable_t *files_enable);
/*@
@ requires \valid(file_recovery);
@ requires valid_file_recovery(file_recovery);
@ requires buffer_size < 1<<30;
@ requires \valid_read((char *)buffer+(0..buffer_size-1));
@ requires new_ext==\null || valid_read_string(new_ext);
@ requires new_ext==\null || (valid_read_string(new_ext) && strlen(new_ext) < 1<<30);
@ ensures valid_file_recovery(file_recovery);
@*/
int file_rename(file_recovery_t *file_recovery, const void *buffer, const int buffer_size, const int offset, const char *new_ext, const int force_ext);
/*@
@ requires \valid(file_recovery);
@ requires new_ext==\null || valid_read_string(new_ext);
@ requires new_ext==\null || (valid_read_string(new_ext) && strlen(new_ext) < 1<<30);
@ requires valid_file_recovery(file_recovery);
@ requires buffer_size < 1<<30;
@ requires \valid_read((char *)buffer+(0..buffer_size-1));
@ ensures valid_file_recovery(file_recovery);
@*/