diff --git a/infer/models/c/src/glib.c b/infer/models/c/src/glib.c index 078124bde..79c1beeb1 100644 --- a/infer/models/c/src/glib.c +++ b/infer/models/c/src/glib.c @@ -33,11 +33,11 @@ void* g_realloc(void* ptr, size_t size) { return NULL; } int old_size; - old_size = __get_array_size(ptr); // force ptr to be an array + old_size = __get_array_length(ptr); // force ptr to be an array int can_enlarge; // nondeterministically choose whether the current block can // be enlarged if (can_enlarge) { - __set_array_size(ptr, size); // enlarge the block + __set_array_length(ptr, size); // enlarge the block return ptr; } int* newblock = (int*)malloc(size); diff --git a/infer/models/c/src/infer_builtins.h b/infer/models/c/src/infer_builtins.h index 6cca798a7..ce0a1bcfe 100644 --- a/infer/models/c/src/infer_builtins.h +++ b/infer/models/c/src/infer_builtins.h @@ -61,13 +61,13 @@ clock_t __infer_nondet_clock_t(); extern void __require_allocated_array(const void* arr); // builtin: return the size of arr -extern size_t __get_array_size(const void* arr); +extern size_t __get_array_length(const void* arr); // builtin: change the attribute of ret to a file attribute extern void __set_file_attribute(void* ret); // builtin: change the size of the array to size -extern void __set_array_size(void* ptr, size_t size); +extern void __set_array_length(void* ptr, size_t size); // builtin: set the flag to the given value for the procedure where this call // appears diff --git a/infer/models/c/src/libc_basic.c b/infer/models/c/src/libc_basic.c index e636e5df1..826ab7bfa 100644 --- a/infer/models/c/src/libc_basic.c +++ b/infer/models/c/src/libc_basic.c @@ -84,9 +84,9 @@ char* strcpy(char* s1, const char* s2) { __infer_set_flag("ignore_return", ""); // no warnings if the return value is ignored __require_allocated_array(s1); - size1 = __get_array_size(s1); + size1 = __get_array_length(s1); __require_allocated_array(s2); - size2 = __get_array_size(s2); + size2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION(size2 > size1); return s1; } @@ -96,7 +96,7 @@ char* strcpy(char* s1, const char* s2) { char* strdup(const char* s) { int size; __require_allocated_array(s); - size = __get_array_size(s); + size = __get_array_length(s); return (char*)malloc(size); } @@ -106,9 +106,9 @@ char* strcat(char* s1, const char* s2) { int size1; int size2; __require_allocated_array(s1); - size1 = __get_array_size(s1); + size1 = __get_array_length(s1); __require_allocated_array(s2); - size2 = __get_array_size(s2); + size2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION(size2 > size1); return s1; } @@ -133,7 +133,7 @@ char* strchr(char* s, int c) throw() { offset = __infer_nondet_int(); __require_allocated_array(s); - size = __get_array_size(s); + size = __get_array_length(s); if (nondet) return 0; INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size); @@ -167,7 +167,7 @@ int strcmp(const char* s1, const char* s2) { size_t strlen(const char* s) { int size; __require_allocated_array(s); - size = __get_array_size(s); + size = __get_array_length(s); return size - 1; } @@ -185,9 +185,9 @@ char* strncat(char* s1, const char* s2, size_t n) { int size_s1; int size_s2; __require_allocated_array(s1); - size_s1 = __get_array_size(s1); + size_s1 = __get_array_length(s1); __require_allocated_array(s2); - size_s2 = __get_array_size(s2); + size_s2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2)); return s1; } @@ -201,9 +201,9 @@ int strncmp(const char* s1, const char* s2, size_t n) { int res; res = __infer_nondet_int(); __require_allocated_array(s1); - size_s1 = __get_array_size(s1); + size_s1 = __get_array_length(s1); __require_allocated_array(s2); - size_s2 = __get_array_size(s2); + size_s2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2)); return res; } @@ -216,7 +216,7 @@ char* strncpy(char* s1, const char* s2, size_t n) { __infer_set_flag("ignore_return", ""); // no warnings if the return value is ignored __require_allocated_array(s1); - size1 = __get_array_size(s1); + size1 = __get_array_length(s1); __require_allocated_array(s2); INFER_EXCLUDE_CONDITION(n > size1); return s1; @@ -237,7 +237,7 @@ char* strpbrk(char* s1, const char* s2) throw() { nondet = __infer_nondet_int(); offset = __infer_nondet_int(); __require_allocated_array(s1); - size1 = __get_array_size(s1); + size1 = __get_array_length(s1); __require_allocated_array(s2); if (nondet) return 0; @@ -252,7 +252,7 @@ size_t strspn(const char* s1, const char* s2) { int res; res = __infer_nondet_int(); __require_allocated_array(s1); - size_s1 = __get_array_size(s1); + size_s1 = __get_array_length(s1); __require_allocated_array(s2); INFER_EXCLUDE_CONDITION(res < 0 || res > size_s1); return res; @@ -274,7 +274,7 @@ char* strstr(char* s1, const char* s2) throw() { nondet = __infer_nondet_int(); offset = __infer_nondet_int(); __require_allocated_array(s1); - size1 = __get_array_size(s1); + size1 = __get_array_length(s1); __require_allocated_array(s2); if (nondet) return 0; @@ -300,7 +300,7 @@ unsigned long strtoul(const char* str, char** endptr, int base) { int offset; int res; __require_allocated_array(str); - size = __get_array_size(str); + size = __get_array_length(str); offset = __infer_nondet_int(); INFER_EXCLUDE_CONDITION(offset < 0 || offset >= size); if (endptr) @@ -338,7 +338,7 @@ void* memchr(void* s, int c, size_t n) throw() { nondet = __infer_nondet_int(); offset = __infer_nondet_int(); __require_allocated_array(s); - size = __get_array_size(s); + size = __get_array_length(s); INFER_EXCLUDE_CONDITION(n > size); if (nondet) return 0; @@ -353,9 +353,9 @@ int memcmp(const void* s1, const void* s2, size_t n) { int size_s1; int size_s2; __require_allocated_array(s1); - size_s1 = __get_array_size(s1); + size_s1 = __get_array_length(s1); __require_allocated_array(s2); - size_s2 = __get_array_size(s2); + size_s2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION((n > size_s1) || (n > size_s2)); return __infer_nondet_int(); } @@ -368,9 +368,9 @@ void* memcpy(void* s1, const void* s2, size_t n) { __infer_set_flag("ignore_return", ""); // no warnings if the return value is ignored __require_allocated_array(s1); - size_s1 = __get_array_size(s1); + size_s1 = __get_array_length(s1); __require_allocated_array(s2); - size_s2 = __get_array_size(s2); + size_s2 = __get_array_length(s2); INFER_EXCLUDE_CONDITION((n < 0) || (n > size_s1) || (n > size_s2)); return s1; } @@ -389,7 +389,7 @@ void* memset(void* s, int c, size_t n) { __infer_set_flag("ignore_return", ""); // no warnings if the return value is ignored __require_allocated_array(s); - size_s = __get_array_size(s); + size_s = __get_array_length(s); INFER_EXCLUDE_CONDITION(n > size_s); return s; } @@ -434,7 +434,7 @@ char* tmpnam(char* s) { return NULL; if (s) { __require_allocated_array(s); - size = __get_array_size(s); + size = __get_array_length(s); INFER_EXCLUDE_CONDITION(size < L_tmpnam); return s; } else @@ -535,7 +535,7 @@ char* fgets(char* str, int num, FILE* stream) { if (n > 0) { __require_allocated_array(str); - size1 = __get_array_size(str); + size1 = __get_array_length(str); INFER_EXCLUDE_CONDITION(num > size1); return str; } else @@ -614,7 +614,7 @@ char* getcwd(char* buffer, size_t size) { if (n > 0) { __require_allocated_array(buffer); - size_buf = __get_array_size(buffer); + size_buf = __get_array_length(buffer); INFER_EXCLUDE_CONDITION(size > size_buf); return buffer; } else @@ -753,7 +753,7 @@ void* realloc(void* ptr, size_t size) { can_enlarge = __infer_nondet_int(); // nondeterministically choose whether the // current block can be enlarged if (can_enlarge) { - __set_array_size(ptr, size); // enlarge the block + __set_array_length(ptr, size); // enlarge the block return ptr; } int* newblock = (int*)malloc(size); @@ -1167,7 +1167,7 @@ size_t strlcpy(char* dst, const char* src, size_t size) { // force dst to be allocated for at least size __require_allocated_array(dst); - size_dst = __get_array_size(dst); + size_dst = __get_array_length(dst); INFER_EXCLUDE_CONDITION(size > size_dst); INFER_EXCLUDE_CONDITION(res > size || res < 0); @@ -1188,7 +1188,7 @@ size_t strlcat(char* dst, const char* src, size_t size) { // force dst to be allocated for at least size __require_allocated_array(dst); - size_dst = __get_array_size(dst); + size_dst = __get_array_length(dst); INFER_EXCLUDE_CONDITION(size > size_dst); INFER_EXCLUDE_CONDITION(res > size || res < 0); @@ -1533,7 +1533,7 @@ ssize_t read(int fildes, void* buf, size_t nbyte) { if (nbyte == 0) return 0; __require_allocated_array(buf); - INFER_EXCLUDE_CONDITION(__get_array_size(buf) < nbyte); + INFER_EXCLUDE_CONDITION(__get_array_length(buf) < nbyte); int ret = __infer_nondet_int(); INFER_EXCLUDE_CONDITION(ret < -1 || ret > nbyte); @@ -1665,7 +1665,7 @@ size_t strcspn(const char* s1, const char* s2) { #if defined __APPLE__ || (defined __USE_XOPEN2K && !defined __USE_GNU) int strerror_r(int errnum, char* strerrbuf, size_t buflen) { __require_allocated_array(strerrbuf); - INFER_EXCLUDE_CONDITION(__get_array_size(strerrbuf) < buflen); + INFER_EXCLUDE_CONDITION(__get_array_length(strerrbuf) < buflen); return __infer_nondet_int(); } @@ -1673,7 +1673,7 @@ int strerror_r(int errnum, char* strerrbuf, size_t buflen) { ssize_t write(int fildes, const void* buf, size_t nbyte) { __require_allocated_array(buf); - INFER_EXCLUDE_CONDITION(__get_array_size(buf) < nbyte); + INFER_EXCLUDE_CONDITION(__get_array_length(buf) < nbyte); int ret = __infer_nondet_int(); INFER_EXCLUDE_CONDITION(ret < -1 || nbyte < ret); @@ -1731,7 +1731,7 @@ void* bsearch(const void* key, nondet = __infer_nondet_int(); offset = __infer_nondet_int(); __require_allocated_array(base); - base_size = __get_array_size(base); + base_size = __get_array_length(base); INFER_EXCLUDE_CONDITION(nmemb > base_size); if (nondet) return 0; diff --git a/infer/models/c/src/wchar.c b/infer/models/c/src/wchar.c index ebb8c32d2..8f5b3e64f 100644 --- a/infer/models/c/src/wchar.c +++ b/infer/models/c/src/wchar.c @@ -127,7 +127,7 @@ int CLIBCALL swprintf(wchar_t* restrict s, ...) { int res; int size1; - size1 = __get_array_size(s); + size1 = __get_array_length(s); res = __infer_nondet_int(); INFER_EXCLUDE_CONDITION(res < 0); return res; diff --git a/infer/models/objc/src/CoreFoundation/CFString.c b/infer/models/objc/src/CoreFoundation/CFString.c index 16a4dbf93..01d979c8d 100644 --- a/infer/models/objc/src/CoreFoundation/CFString.c +++ b/infer/models/objc/src/CoreFoundation/CFString.c @@ -12,7 +12,7 @@ CFStringRef __cf_alloc(CFStringRef); -void __get_array_size(const UInt8); +void __get_array_length(const UInt8); CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8* bytes, @@ -24,7 +24,7 @@ CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, CFStringRef s = __cf_alloc(c); if (s) { if (bytes) { - __get_array_size(bytes); + __get_array_length(bytes); free(bytes); } } diff --git a/infer/models/objc/src/NSString.m b/infer/models/objc/src/NSString.m index ad7706407..2cc19a48c 100644 --- a/infer/models/objc/src/NSString.m +++ b/infer/models/objc/src/NSString.m @@ -10,7 +10,7 @@ #import "NSString.h" #import -void __get_array_size(const UInt8); +void __get_array_length(const UInt8); @implementation NSString @@ -41,7 +41,7 @@ void __get_array_size(const UInt8); freeWhenDone:(BOOL)flag { if (flag == YES) { if (bytes) { - __get_array_size(bytes); + __get_array_length(bytes); free(bytes); } } diff --git a/infer/src/IR/Sil.re b/infer/src/IR/Sil.re index e99fe8995..da4cbb4cb 100644 --- a/infer/src/IR/Sil.re +++ b/infer/src/IR/Sil.re @@ -741,6 +741,10 @@ and struct_typ = { def_methods: list Procname.t, /** methods defined */ struct_annotations: item_annotation /** annotations */ } +/** statically determined length of an array type, if any */ +and static_length = option Int.t +/** dynamically determined length of an array value, if any */ +and dynamic_length = option exp /** types for sil (structured) expressions */ and typ = | Tvar of Typename.t /** named type */ @@ -750,7 +754,7 @@ and typ = | Tfun of bool /** function type with noreturn attribute */ | Tptr of typ ptr_kind /** pointer type */ | Tstruct of struct_typ /** Type for a structured value */ - | Tarray of typ exp /** array type with fixed size */ + | Tarray of typ static_length /** array type with statically fixed length */ /** Program expressions. */ and exp = /** Pure variable: it is not an lvalue */ @@ -769,10 +773,24 @@ and exp = | Lfield of exp Ident.fieldname typ /** An array index offset: [exp1\[exp2\]] */ | Lindex of exp exp - /** A sizeof expression. [Sizeof typ (Some len)] represents the size of a value of type [typ] - which ends in an extensible array of length [len]. The lengths in [Tarray] record the - statically determined lengths, while the lengths in [Sizeof] record the dynamic lengths. */ - | Sizeof of typ (option exp) Subtype.t; + /** A sizeof expression. [Sizeof (Tarray elt (Some static_length)) (Some dynamic_length)] + represents the size of an array value consisting of [dynamic_length] elements of type [elt]. + The [dynamic_length], tracked by symbolic execution, may differ from the [static_length] + obtained from the type definition, e.g. when an array is over-allocated. For struct types, + the [dynamic_length] is that of the final extensible array, if any. */ + | Sizeof of typ dynamic_length Subtype.t; + + +/** the element typ of the final extensible array in the given typ, if any */ +let rec get_extensible_array_element_typ = + fun + | Tarray typ _ => Some typ + | Tstruct {instance_fields} => + Option.map_default + (fun (_, fld_typ, _) => get_extensible_array_element_typ fld_typ) + None + (IList.last instance_fields) + | _ => None; /** Kind of prune instruction */ @@ -873,10 +891,10 @@ type inst = type strexp = | Eexp of exp inst /** Base case: expression with instrumentation */ | Estruct of (list (Ident.fieldname, strexp)) inst /** C structure */ - | Earray of exp (list (exp, strexp)) inst /** Array of given size. */ + | Earray of exp (list (exp, strexp)) inst /** Array of given length */ /** There are two conditions imposed / used in the array case. First, if some index and value pair appears inside an array - in a strexp, then the index is less than the size of the array. + in a strexp, then the index is less than the length of the array. For instance, x |->[10 | e1: v1] implies that e1 <= 9. Second, if two indices appear in an array, they should be different. For instance, x |->[10 | e1: v1, e2: v2] implies that e1 != e2. */ @@ -2343,8 +2361,8 @@ and pp_struct_typ pe pp_base f struct_typ => } /** Pretty print a type declaration. pp_base prints the variable for a declaration, or can be skip to print only the type - pp_size prints the expression for the array size */ -and pp_type_decl pe pp_base pp_size f => + pp_static_len prints the expression for the array length */ +and pp_type_decl pe pp_base pp_static_len f => fun | Tvar tname => F.fprintf f "%s %a" (Typename.to_string tname) pp_base () | Tint ik => F.fprintf f "%s %a" (ikind_to_string ik) pp_base () @@ -2354,16 +2372,21 @@ and pp_type_decl pe pp_base pp_size f => | Tfun true => F.fprintf f "_fn_noreturn_ %a" pp_base () | Tptr ((Tarray _ | Tfun _) as typ) pk => { let pp_base' fmt () => F.fprintf fmt "(%s%a)" (ptr_kind_string pk) pp_base (); - pp_type_decl pe pp_base' pp_size f typ + pp_type_decl pe pp_base' pp_static_len f typ } | Tptr typ pk => { let pp_base' fmt () => F.fprintf fmt "%s%a" (ptr_kind_string pk) pp_base (); - pp_type_decl pe pp_base' pp_size f typ + pp_type_decl pe pp_base' pp_static_len f typ } | Tstruct struct_typ => pp_struct_typ pe pp_base f struct_typ - | Tarray typ size => { - let pp_base' fmt () => F.fprintf fmt "%a[%a]" pp_base () (pp_size pe) size; - pp_type_decl pe pp_base' pp_size f typ + | Tarray typ static_len => { + let pp_array_static_len fmt => ( + fun + | Some static_len => pp_static_len pe fmt (Const (Cint static_len)) + | None => F.fprintf fmt "_" + ); + let pp_base' fmt () => F.fprintf fmt "%a[%a]" pp_base () pp_array_static_len static_len; + pp_type_decl pe pp_base' pp_static_len f typ } /** Pretty print a type with all the details, using the C syntax. */ and pp_typ_full pe => pp_type_decl pe (fun _ () => ()) pp_exp_full @@ -2994,10 +3017,9 @@ let rec pp_sexp_env pe0 envo f se => { F.fprintf f "%a:%a" (Ident.pp_fieldname_latex Latex.Boldface) n (pp_sexp_env pe envo) se; F.fprintf f "\\{%a\\}%a" (pp_seq_diff pp_diff pe) fel (pp_inst_if_trace pe) inst } - | Earray size nel inst => + | Earray len nel inst => let pp_diff f (i, se) => F.fprintf f "%a:%a" (pp_exp pe) i (pp_sexp_env pe envo) se; - F.fprintf - f "[%a|%a]%a" (pp_exp pe) size (pp_seq_diff pp_diff pe) nel (pp_inst_if_trace pe) inst + F.fprintf f "[%a|%a]%a" (pp_exp pe) len (pp_seq_diff pp_diff pe) nel (pp_inst_if_trace pe) inst }; color_post_wrapper changed pe0 f } @@ -3205,13 +3227,13 @@ let rec strexp_expmap (f: (exp, option inst) => (exp, option inst)) => { let f_fld_se (fld, se) => (fld, strexp_expmap f se); Estruct (IList.map f_fld_se fld_se_list) inst } - | Earray size idx_se_list inst => { - let size' = fe size; + | Earray len idx_se_list inst => { + let len' = fe len; let f_idx_se (idx, se) => { let idx' = fe idx; (idx', strexp_expmap f se) }; - Earray size' (IList.map f_idx_se idx_se_list) inst + Earray len' (IList.map f_idx_se idx_se_list) inst } }; @@ -3246,9 +3268,9 @@ let rec strexp_instmap (f: inst => inst) strexp => | Estruct fld_se_list inst => let f_fld_se (fld, se) => (fld, strexp_instmap f se); Estruct (IList.map f_fld_se fld_se_list) (f inst) - | Earray size idx_se_list inst => + | Earray len idx_se_list inst => let f_idx_se (idx, se) => (idx, strexp_instmap f se); - Earray size (IList.map f_idx_se idx_se_list) (f inst) + Earray len (IList.map f_idx_se idx_se_list) (f inst) } and hpara_instmap (f: inst => inst) hpara => { ...hpara, @@ -3449,10 +3471,10 @@ let rec strexp_fpv = let f (_, se) => strexp_fpv se; IList.flatten (IList.map f fld_se_list) } - | Earray size idx_se_list _ => { - let fpv_in_size = exp_fpv size; + | Earray len idx_se_list _ => { + let fpv_in_len = exp_fpv len; let f (idx, se) => exp_fpv idx @ strexp_fpv se; - fpv_in_size @ IList.flatten (IList.map f idx_se_list) + fpv_in_len @ IList.flatten (IList.map f idx_se_list) } and hpred_fpv = fun @@ -3662,8 +3684,8 @@ let rec strexp_fav_add fav => fun | Eexp e _ => exp_fav_add fav e | Estruct fld_se_list _ => IList.iter (fun (_, se) => strexp_fav_add fav se) fld_se_list - | Earray size idx_se_list _ => { - exp_fav_add fav size; + | Earray len idx_se_list _ => { + exp_fav_add fav len; IList.iter ( fun (e, se) => { @@ -4015,18 +4037,7 @@ let sub_fpv (sub: subst) => IList.flatten (IList.map (fun (_, e) => exp_fpv e) s /** Substitutions do not contain binders */ let sub_av_add = sub_fav_add; -let rec typ_sub (subst: subst) typ => - switch typ { - | Tvar _ - | Tint _ - | Tfloat _ - | Tvoid - | Tstruct _ - | Tfun _ => typ - | Tptr t' pk => Tptr (typ_sub subst t') pk - | Tarray t e => Tarray (typ_sub subst t) (exp_sub subst e) - } -and exp_sub (subst: subst) e => +let rec exp_sub (subst: subst) e => switch e { | Var id => let rec apply_sub = ( @@ -4053,12 +4064,7 @@ and exp_sub (subst: subst) e => Cast t e1' | UnOp op e1 typo => let e1' = exp_sub subst e1; - let typo' = - switch typo { - | None => None - | Some typ => Some (typ_sub subst typ) - }; - UnOp op e1' typo' + UnOp op e1' typo | BinOp op e1 e2 => let e1' = exp_sub subst e1; let e2' = exp_sub subst e2; @@ -4066,13 +4072,12 @@ and exp_sub (subst: subst) e => | Lvar _ => e | Lfield e1 fld typ => let e1' = exp_sub subst e1; - let typ' = typ_sub subst typ; - Lfield e1' fld typ' + Lfield e1' fld typ | Lindex e1 e2 => let e1' = exp_sub subst e1; let e2' = exp_sub subst e2; Lindex e1' e2' - | Sizeof t l s => Sizeof (typ_sub subst t) (Option.map (exp_sub subst) l) s + | Sizeof t l s => Sizeof t (Option.map (exp_sub subst) l) s }; let instr_sub (subst: subst) instr => { @@ -4082,20 +4087,19 @@ let instr_sub (subst: subst) instr => { | _ => id }; let exp_s = exp_sub subst; - let typ_s = typ_sub subst; switch instr { - | Letderef id e t loc => Letderef (id_s id) (exp_s e) (typ_s t) loc - | Set e1 t e2 loc => Set (exp_s e1) (typ_s t) (exp_s e2) loc + | Letderef id e t loc => Letderef (id_s id) (exp_s e) t loc + | Set e1 t e2 loc => Set (exp_s e1) t (exp_s e2) loc | Prune cond loc true_branch ik => Prune (exp_s cond) loc true_branch ik | Call ret_ids e arg_ts loc cf => - let arg_s (e, t) => (exp_s e, typ_s t); + let arg_s (e, t) => (exp_s e, t); Call (IList.map id_s ret_ids) (exp_s e) (IList.map arg_s arg_ts) loc cf | Nullify _ => instr | Abstract _ => instr | Remove_temps temps loc => Remove_temps (IList.map id_s temps) loc | Stackop _ => instr | Declare_locals ptl loc => - let pt_s (pv, t) => (pv, typ_s t); + let pt_s (pv, t) => (pv, t); Declare_locals (IList.map pt_s ptl) loc } }; @@ -4512,13 +4516,13 @@ let rec strexp_replace_exp epairs => let f (fld, se) => (fld, strexp_replace_exp epairs se); Estruct (IList.map f fsel) inst } - | Earray size isel inst => { - let size' = exp_replace_exp epairs size; + | Earray len isel inst => { + let len' = exp_replace_exp epairs len; let f (idx, se) => { let idx' = exp_replace_exp epairs idx; (idx', strexp_replace_exp epairs se) }; - Earray size' (IList.map f isel) inst + Earray len' (IList.map f isel) inst }; let hpred_replace_exp epairs => diff --git a/infer/src/IR/Sil.rei b/infer/src/IR/Sil.rei index c4ec13d71..ecef79342 100644 --- a/infer/src/IR/Sil.rei +++ b/infer/src/IR/Sil.rei @@ -314,6 +314,10 @@ and struct_typ = { def_methods: list Procname.t, /** methods defined */ struct_annotations: item_annotation /** annotations */ } +/** statically determined length of an array type, if any */ +and static_length = option Int.t +/** dynamically determined length of an array value, if any */ +and dynamic_length = option exp /** Types for sil (structured) expressions. */ and typ = | Tvar of Typename.t /** named type */ @@ -323,7 +327,7 @@ and typ = | Tfun of bool /** function type with noreturn attribute */ | Tptr of typ ptr_kind /** pointer type */ | Tstruct of struct_typ /** Type for a structured value */ - | Tarray of typ exp /** array type with fixed size */ + | Tarray of typ static_length /** array type with statically fixed length */ /** Program expressions. */ and exp = /** Pure variable: it is not an lvalue */ @@ -342,8 +346,14 @@ and exp = | Lfield of exp Ident.fieldname typ /** An array index offset: [exp1\[exp2\]] */ | Lindex of exp exp - /** A sizeof expression */ - | Sizeof of typ (option exp) Subtype.t; + /** A sizeof expression. [Sizeof typ (Some len)] represents the size of a value of type [typ] + which ends in an extensible array of length [len]. The length in [Tarray] records the + statically determined length, while the length in [Sizeof] records the dynamic length. */ + | Sizeof of typ dynamic_length Subtype.t; + + +/** the element typ of the final extensible array in the given typ, if any */ +let get_extensible_array_element_typ: typ => option typ; let struct_typ_equal: struct_typ => struct_typ => bool; @@ -528,10 +538,10 @@ let inst_partial_meet: inst => inst => inst; type strexp = | Eexp of exp inst /** Base case: expression with instrumentation */ | Estruct of (list (Ident.fieldname, strexp)) inst /** C structure */ - | Earray of exp (list (exp, strexp)) inst /** Array of given size. */ + | Earray of exp (list (exp, strexp)) inst /** Array of given length */ /** There are two conditions imposed / used in the array case. First, if some index and value pair appears inside an array - in a strexp, then the index is less than the size of the array. + in a strexp, then the index is less than the length of the array. For instance, x |->[10 | e1: v1] implies that e1 <= 9. Second, if two indices appear in an array, they should be different. For instance, x |->[10 | e1: v1, e2: v2] implies that e1 != e2. */ @@ -886,9 +896,9 @@ let pp_typ_full: printenv => F.formatter => typ => unit; let typ_to_string: typ => string; -/** [pp_type_decl pe pp_base pp_size f typ] pretty prints a type declaration. +/** [pp_type_decl pe pp_base pp_len f typ] pretty prints a type declaration. pp_base prints the variable for a declaration, or can be skip to print only the type - pp_size prints the expression for the array size */ + pp_len prints the expression for the array length */ let pp_type_decl: printenv => (F.formatter => unit => unit) => diff --git a/infer/src/IR/Tenv.re b/infer/src/IR/Tenv.re index c3bada373..a47488ce6 100644 --- a/infer/src/IR/Tenv.re +++ b/infer/src/IR/Tenv.re @@ -57,9 +57,8 @@ let lookup_java_typ_from_string tenv typ_str => { | "double" => Some (Sil.Tfloat Sil.FDouble) | typ_str when String.contains typ_str '[' => { let stripped_typ = String.sub typ_str 0 (String.length typ_str - 2); - let array_typ_size = Sil.exp_get_undefined false; switch (loop stripped_typ) { - | Some typ => Some (Sil.Tptr (Sil.Tarray typ array_typ_size) Sil.Pk_pointer) + | Some typ => Some (Sil.Tptr (Sil.Tarray typ None) Sil.Pk_pointer) | None => None } } diff --git a/infer/src/backend/abs.ml b/infer/src/backend/abs.ml index a1af433cc..e9a63edd5 100644 --- a/infer/src/backend/abs.ml +++ b/infer/src/backend/abs.ml @@ -903,14 +903,14 @@ let get_cycle root prop = let visited' = (fst et_src):: visited in let res = (match get_points_to e with | None -> path, false - | Some (Sil.Hpointsto(_, Sil.Estruct(fl, _), Sil.Sizeof(te, _, _))) -> + | Some (Sil.Hpointsto (_, Sil.Estruct (fl, _), Sil.Sizeof (te, _, _))) -> dfs e_root (e, te) ((et_src, f, e):: path) fl visited' | _ -> path, false (* check for lists *)) in if snd res then res else dfs e_root et_src path el' visited') in L.d_strln "Looking for cycle with root expression: "; Sil.d_hpred root; L.d_strln ""; match root with - | Sil.Hpointsto(e_root, Sil.Estruct(fl, _), Sil.Sizeof(te, _, _)) -> + | Sil.Hpointsto (e_root, Sil.Estruct (fl, _), Sil.Sizeof (te, _, _)) -> let se_root = Sil.Eexp(e_root, Sil.Inone) in (* start dfs with empty path and expr pointing to root *) let (pot_cycle, res) = dfs se_root (se_root, te) [] fl [] in @@ -949,7 +949,7 @@ let get_var_retain_cycle _prop = | _ -> false in let is_hpred_block v h = match h, v with - | Sil.Hpointsto (e, _, Sil.Sizeof(typ, _, _)), Sil.Eexp (e', _) + | Sil.Hpointsto (e, _, Sil.Sizeof (typ, _, _)), Sil.Eexp (e', _) when Sil.exp_equal e e' && Sil.is_block_type typ -> true | _, _ -> false in let find v = diff --git a/infer/src/backend/absarray.ml b/infer/src/backend/absarray.ml index 904a90bf6..f274cbebf 100644 --- a/infer/src/backend/absarray.ml +++ b/infer/src/backend/absarray.ml @@ -28,7 +28,7 @@ module StrexpMatch : sig (** create a path from a root and a list of offsets *) val path_from_exp_offsets : Sil.exp -> Sil.offset list -> path - (** path to the root, size, elements and type of a new_array *) + (** path to the root, length, elements and type of a new_array *) type strexp_data = path * Sil.strexp * Sil.typ (** sigma with info about a current array *) @@ -73,7 +73,7 @@ end = struct (IList.find (fun (f', _, _) -> Sil.fld_equal f' fld) instance_fields) in get_strexp_at_syn_offsets se' t' syn_offs' - | Sil.Earray (_, esel, _), Sil.Tarray(t', _), Index ind :: syn_offs' -> + | Sil.Earray (_, esel, _), Sil.Tarray (t', _), Index ind :: syn_offs' -> let se' = snd (IList.find (fun (i', _) -> Sil.exp_equal i' ind) esel) in get_strexp_at_syn_offsets se' t' syn_offs' | _ -> @@ -95,11 +95,11 @@ end = struct let se_mod = replace_strexp_at_syn_offsets se' t' syn_offs' update in let fsel' = IList.map (fun (f'', se'') -> if Sil.fld_equal f'' fld then (fld, se_mod) else (f'', se'')) fsel in Sil.Estruct (fsel', inst) - | Sil.Earray (size, esel, inst), Sil.Tarray (t', _), Index idx :: syn_offs' -> + | Sil.Earray (len, esel, inst), Sil.Tarray (t', _), Index idx :: syn_offs' -> let se' = snd (IList.find (fun (i', _) -> Sil.exp_equal i' idx) esel) in let se_mod = replace_strexp_at_syn_offsets se' t' syn_offs' update in let esel' = IList.map (fun ese -> if Sil.exp_equal (fst ese) idx then (idx, se_mod) else ese) esel in - Sil.Earray (size, esel', inst) + Sil.Earray (len, esel', inst) | _ -> assert false (** convert a path into an expression *) @@ -124,7 +124,7 @@ end = struct let syn_offs = IList.map offset_to_syn_offset offs in (root, syn_offs) - (** path to the root, size, elements and type of a new_array *) + (** path to the root, len, elements and type of a new_array *) type strexp_data = path * Sil.strexp * Sil.typ (** Store hpred using physical equality, and offset list for an array *) @@ -205,13 +205,13 @@ end = struct let update se' = let se_in = update se' in match se', se_in with - | Sil.Earray (size, esel, _), Sil.Earray (_, esel_in, inst2) -> + | Sil.Earray (len, esel, _), Sil.Earray (_, esel_in, inst2) -> let orig_indices = IList.map fst esel in let index_is_not_new idx = IList.exists (Sil.exp_equal idx) orig_indices in let process_index idx = if index_is_not_new idx then idx else (Sil.array_clean_new_index footprint_part idx) in let esel_in' = IList.map (fun (idx, se) -> process_index idx, se) esel_in in - Sil.Earray (size, esel_in', inst2) + Sil.Earray (len, esel_in', inst2) | _, _ -> se_in in begin match hpred with @@ -232,9 +232,9 @@ end = struct let replace_index footprint_part ((sigma, hpred, syn_offs) : t) (index: Sil.exp) (index': Sil.exp) = let update se' = match se' with - | Sil.Earray (size, esel, inst) -> + | Sil.Earray (len, esel, inst) -> let esel' = IList.map (fun (e', se') -> if Sil.exp_equal e' index then (index', se') else (e', se')) esel in - Sil.Earray (size, esel', inst) + Sil.Earray (len, esel', inst) | _ -> assert false in let hpred' = hpred_replace_strexp footprint_part hpred syn_offs update in replace_hpred (sigma, hpred, syn_offs) hpred' @@ -413,11 +413,11 @@ let keep_only_indices let matched = StrexpMatch.find_path sigma path in let (_, se, _) = StrexpMatch.get_data matched in match se with - | Sil.Earray (size, esel, inst) -> + | Sil.Earray (len, esel, inst) -> let esel', esel_leftover' = IList.partition (fun (e, _) -> IList.exists (Sil.exp_equal e) indices) esel in if esel_leftover' == [] then (sigma, false) else begin - let se' = Sil.Earray (size, esel', inst) in + let se' = Sil.Earray (len, esel', inst) in let sigma' = StrexpMatch.replace_strexp footprint_part matched se' in (sigma', true) end @@ -584,9 +584,9 @@ let remove_redundant_elements prop = remove () (* index unknown can be removed *) | _ -> true in let remove_redundant_se fp_part = function - | Sil.Earray (size, esel, inst) -> + | Sil.Earray (len, esel, inst) -> let esel' = IList.filter (filter_redundant_e_se fp_part) esel in - Sil.Earray (size, esel', inst) + Sil.Earray (len, esel', inst) | se -> se in let remove_redundant_hpred fp_part = function | Sil.Hpointsto (e, se, te) -> diff --git a/infer/src/backend/autounit.ml b/infer/src/backend/autounit.ml index 7fb99f361..6f4b19133 100644 --- a/infer/src/backend/autounit.ml +++ b/infer/src/backend/autounit.ml @@ -307,8 +307,8 @@ let create_idmap sigma : idmap = do_exp e typ | Sil.Estruct (fsel, _), Sil.Tstruct { Sil.instance_fields } -> do_struct fsel instance_fields - | Sil.Earray (size, esel, _), Sil.Tarray (typ, _) -> - do_se (Sil.Eexp (size, Sil.inst_none)) (Sil.Tint Sil.IULong); + | Sil.Earray (len, esel, _), Sil.Tarray (typ, _) -> + do_se (Sil.Eexp (len, Sil.inst_none)) (Sil.Tint Sil.IULong); do_array esel typ | _ -> L.err "Unmatched sexp: %a : %a@." (Sil.pp_sexp pe) se (Sil.pp_typ_full pe) typ; @@ -415,20 +415,20 @@ let mk_size_name id = "_size_" ^ string_of_int id let pp_texp_for_malloc fmt = - let rec handle_arr_size typ = match typ with + let rec handle_arr_len typ = match typ with | Sil.Tvar _ | Sil.Tint _ | Sil.Tfloat _ | Sil.Tvoid | Sil.Tfun _ -> typ | Sil.Tptr (t, pk) -> - Sil.Tptr (handle_arr_size t, pk) + Sil.Tptr (handle_arr_len t, pk) | Sil.Tstruct struct_typ -> let instance_fields = - IList.map (fun (f, t, a) -> (f, handle_arr_size t, a)) struct_typ.Sil.instance_fields in + IList.map (fun (f, t, a) -> (f, handle_arr_len t, a)) struct_typ.Sil.instance_fields in Sil.Tstruct { struct_typ with Sil.instance_fields } | Sil.Tarray (t, e) -> - Sil.Tarray (handle_arr_size t, e) in + Sil.Tarray (handle_arr_len t, e) in function | Sil.Sizeof (typ, _, _) -> - let typ' = handle_arr_size typ in + let typ' = handle_arr_len typ in F.fprintf fmt "sizeof(%a)" (pp_typ_c pe) typ' | e -> pp_exp_c pe fmt e diff --git a/infer/src/backend/dom.ml b/infer/src/backend/dom.ml index c4d9f300f..e3c2d625d 100644 --- a/infer/src/backend/dom.ml +++ b/infer/src/backend/dom.ml @@ -877,6 +877,12 @@ let ident_partial_meet (id1: Ident.t) (id2: Ident.t) = (** {2 Join and Meet for Exps} *) +let option_partial_join partial_join o1 o2 = + match o1, o2 with + | None, _ -> o2 + | _, None -> o1 + | Some x1, Some x2 -> partial_join x1 x2 + let const_partial_join c1 c2 = let is_int = function Sil.Cint _ -> true | _ -> false in if Sil.const_equal c1 c2 then Sil.Const c1 @@ -951,35 +957,36 @@ let rec exp_partial_join (e1: Sil.exp) (e2: Sil.exp) : Sil.exp = let e2'' = exp_partial_join e1' e2' in Sil.Lindex(e1'', e2'') | Sil.Sizeof (t1, len1, st1), Sil.Sizeof (t2, len2, st2) -> - Sil.Sizeof (typ_partial_join t1 t2, len_partial_join len1 len2, Sil.Subtype.join st1 st2) + Sil.Sizeof + (typ_partial_join t1 t2, dynamic_length_partial_join len1 len2, Sil.Subtype.join st1 st2) | _ -> L.d_str "exp_partial_join no match "; Sil.d_exp e1; L.d_str " "; Sil.d_exp e2; L.d_ln (); raise IList.Fail -and len_partial_join len1 len2 = - match len1, len2 with - | None, _ -> len2 - | _, None -> len1 - | Some len1, Some len2 -> Some (size_partial_join len1 len2) - -and size_partial_join size1 size2 = match size1, size2 with +and length_partial_join len1 len2 = match len1, len2 with | Sil.BinOp(Sil.PlusA, e1, Sil.Const c1), Sil.BinOp(Sil.PlusA, e2, Sil.Const c2) -> let e' = exp_partial_join e1 e2 in let c' = exp_partial_join (Sil.Const c1) (Sil.Const c2) in Sil.BinOp (Sil.PlusA, e', c') | Sil.BinOp(Sil.PlusA, _, _), Sil.BinOp(Sil.PlusA, _, _) -> - Rename.extend size1 size2 Rename.ExtFresh + Rename.extend len1 len2 Rename.ExtFresh | Sil.Var id1, Sil.Var id2 when Ident.equal id1 id2 -> - size1 - | _ -> exp_partial_join size1 size2 + len1 + | _ -> exp_partial_join len1 len2 + +and static_length_partial_join l1 l2 = + option_partial_join (fun len1 len2 -> if Sil.Int.eq len1 len2 then Some len1 else None) l1 l2 + +and dynamic_length_partial_join l1 l2 = + option_partial_join (fun len1 len2 -> Some (length_partial_join len1 len2)) l1 l2 and typ_partial_join t1 t2 = match t1, t2 with | Sil.Tptr (t1, pk1), Sil.Tptr (t2, pk2) when Sil.ptr_kind_compare pk1 pk2 = 0 -> Sil.Tptr (typ_partial_join t1 t2, pk1) - | Sil.Tarray (typ1, size1), Sil.Tarray(typ2, size2) -> + | Sil.Tarray (typ1, len1), Sil.Tarray (typ2, len2) -> let t = typ_partial_join typ1 typ2 in - let size = size_partial_join size1 size2 in - Sil.Tarray (t, size) + let len = static_length_partial_join len1 len2 in + Sil.Tarray (t, len) | _ when Sil.typ_equal t1 t2 -> t1 (* common case *) | _ -> L.d_str "typ_partial_join no match "; Sil.d_typ_full t1; L.d_str " "; Sil.d_typ_full t2; L.d_ln (); @@ -1072,21 +1079,21 @@ let rec strexp_partial_join mode (strexp1: Sil.strexp) (strexp2: Sil.strexp) : S assert false (* This case should not happen. *) end in - let rec f_idx_se_list inst size idx_se_list_acc idx_se_list1 idx_se_list2 = + let rec f_idx_se_list inst len idx_se_list_acc idx_se_list1 idx_se_list2 = match idx_se_list1, idx_se_list2 with - | [], [] -> Sil.Earray (size, IList.rev idx_se_list_acc, inst) + | [], [] -> Sil.Earray (len, IList.rev idx_se_list_acc, inst) | [], _ | _, [] -> begin match mode with | JoinState.Pre -> (L.d_strln "failure reason 44"; raise IList.Fail) | JoinState.Post -> - Sil.Earray (size, IList.rev idx_se_list_acc, inst) + Sil.Earray (len, IList.rev idx_se_list_acc, inst) end | (idx1, se1):: idx_se_list1', (idx2, se2):: idx_se_list2' -> let idx = exp_partial_join idx1 idx2 in let strexp' = strexp_partial_join mode se1 se2 in let idx_se_list_new = (idx, strexp') :: idx_se_list_acc in - f_idx_se_list inst size idx_se_list_new idx_se_list1' idx_se_list2' in + f_idx_se_list inst len idx_se_list_new idx_se_list1' idx_se_list2' in match strexp1, strexp2 with | Sil.Eexp (e1, inst1), Sil.Eexp (e2, inst2) -> @@ -1094,10 +1101,10 @@ let rec strexp_partial_join mode (strexp1: Sil.strexp) (strexp2: Sil.strexp) : S | Sil.Estruct (fld_se_list1, inst1), Sil.Estruct (fld_se_list2, inst2) -> let inst = Sil.inst_partial_join inst1 inst2 in f_fld_se_list inst mode [] fld_se_list1 fld_se_list2 - | Sil.Earray (size1, idx_se_list1, inst1), Sil.Earray (size2, idx_se_list2, inst2) -> - let size = size_partial_join size1 size2 in + | Sil.Earray (len1, idx_se_list1, inst1), Sil.Earray (len2, idx_se_list2, inst2) -> + let len = length_partial_join len1 len2 in let inst = Sil.inst_partial_join inst1 inst2 in - f_idx_se_list inst size [] idx_se_list1 idx_se_list2 + f_idx_se_list inst len [] idx_se_list1 idx_se_list2 | _ -> L.d_strln "no match in strexp_partial_join"; raise IList.Fail let rec strexp_partial_meet (strexp1: Sil.strexp) (strexp2: Sil.strexp) : Sil.strexp = @@ -1130,19 +1137,19 @@ let rec strexp_partial_meet (strexp1: Sil.strexp) (strexp2: Sil.strexp) : Sil.st let acc_new = (fld1, strexp') :: acc in f_fld_se_list inst acc_new fld_se_list1' fld_se_list2' in - let rec f_idx_se_list inst size acc idx_se_list1 idx_se_list2 = + let rec f_idx_se_list inst len acc idx_se_list1 idx_se_list2 = match idx_se_list1, idx_se_list2 with | [],[] -> - Sil.Earray (size, IList.rev acc, inst) + Sil.Earray (len, IList.rev acc, inst) | [], _ -> - Sil.Earray (size, construct Rhs acc idx_se_list2, inst) + Sil.Earray (len, construct Rhs acc idx_se_list2, inst) | _, [] -> - Sil.Earray (size, construct Lhs acc idx_se_list1, inst) + Sil.Earray (len, construct Lhs acc idx_se_list1, inst) | (idx1, se1):: idx_se_list1', (idx2, se2):: idx_se_list2' -> let idx = exp_partial_meet idx1 idx2 in let se' = strexp_partial_meet se1 se2 in let acc_new = (idx, se') :: acc in - f_idx_se_list inst size acc_new idx_se_list1' idx_se_list2' in + f_idx_se_list inst len acc_new idx_se_list1' idx_se_list2' in match strexp1, strexp2 with | Sil.Eexp (e1, inst1), Sil.Eexp (e2, inst2) -> @@ -1150,10 +1157,10 @@ let rec strexp_partial_meet (strexp1: Sil.strexp) (strexp2: Sil.strexp) : Sil.st | Sil.Estruct (fld_se_list1, inst1), Sil.Estruct (fld_se_list2, inst2) -> let inst = Sil.inst_partial_meet inst1 inst2 in f_fld_se_list inst [] fld_se_list1 fld_se_list2 - | Sil.Earray (size1, idx_se_list1, inst1), Sil.Earray (size2, idx_se_list2, inst2) - when Sil.exp_equal size1 size2 -> + | Sil.Earray (len1, idx_se_list1, inst1), Sil.Earray (len2, idx_se_list2, inst2) + when Sil.exp_equal len1 len2 -> let inst = Sil.inst_partial_meet inst1 inst2 in - f_idx_se_list inst size1 [] idx_se_list1 idx_se_list2 + f_idx_se_list inst len1 [] idx_se_list1 idx_se_list2 | _ -> (L.d_strln "failure reason 52"; raise IList.Fail) (** {2 Join and Meet for kind, hpara, hpara_dll} *) @@ -1554,26 +1561,26 @@ let pi_partial_join mode | Sil.Const _ -> true (* | Sil.Lvar _ -> true *) | _ -> false in - let get_array_size prop = - (* find some array size in the prop, to be used as heuritic for upper bound in widening *) - let size_list = ref [] in + let get_array_len prop = + (* find some array length in the prop, to be used as heuritic for upper bound in widening *) + let len_list = ref [] in let do_hpred = function | Sil.Hpointsto (_, Sil.Earray (Sil.Const (Sil.Cint n), _, _), _) -> - (if Sil.Int.geq n Sil.Int.one then size_list := n::!size_list) + (if Sil.Int.geq n Sil.Int.one then len_list := n :: !len_list) | _ -> () in IList.iter do_hpred (Prop.get_sigma prop); - !size_list in + !len_list in let bounds = - let bounds1 = get_array_size ep1 in - let bounds2 = get_array_size ep2 in + let bounds1 = get_array_len ep1 in + let bounds2 = get_array_len ep2 in let bounds_sorted = IList.sort Sil.Int.compare_value (bounds1@bounds2) in IList.rev (IList.remove_duplicates Sil.Int.compare_value bounds_sorted) in let widening_atom a = - (* widening heuristic for upper bound: take the size of some array, -2 and -1 *) + (* widening heuristic for upper bound: take the length of some array, -2 and -1 *) match Prop.atom_exp_le_const a, bounds with - | Some (e, n), size:: _ -> - let first_try = Sil.Int.sub size Sil.Int.one in - let second_try = Sil.Int.sub size Sil.Int.two in + | Some (e, n), len :: _ -> + let first_try = Sil.Int.sub len Sil.Int.one in + let second_try = Sil.Int.sub len Sil.Int.two in let bound = if Sil.Int.leq n first_try then if Sil.Int.leq n second_try then second_try else first_try @@ -1629,14 +1636,14 @@ let pi_partial_join mode | Some (e, n) -> if IList.exists (is_stronger_le e n) pi_op then (widening_atom a_res) else Some a_res end in - let handle_atom_with_widening size p_op pi_op atom_list a = + let handle_atom_with_widening len p_op pi_op atom_list a = (* find a join for the atom, if it fails apply widening heuristing and try again *) - match join_atom size p_op pi_op a with + match join_atom len p_op pi_op a with | None -> (match widening_atom a with | None -> atom_list | Some a' -> - (match join_atom size p_op pi_op a' with + (match join_atom len p_op pi_op a' with | None -> atom_list | Some a' -> a' :: atom_list)) | Some a' -> a' :: atom_list in diff --git a/infer/src/backend/dotty.ml b/infer/src/backend/dotty.ml index 3e45a9bb3..af548c053 100644 --- a/infer/src/backend/dotty.ml +++ b/infer/src/backend/dotty.ml @@ -65,7 +65,7 @@ type dotty_node = (* Dotstruct(coo,e,l,c): struct box for expression e with field list l at coordinate coo and color c *) | Dotstruct of coordinate * Sil.exp * (Ident.fieldname * Sil.strexp) list * string * Sil.exp (* Dotarray(coo,e1,e2,l,t,c): array box for expression e1 with field list l at coordinate coo and color c*) - (* e2 is the size and t is the type *) + (* e2 is the len and t is the type *) | Dotarray of coordinate * Sil.exp * Sil.exp * (Sil.exp * Sil.strexp) list * Sil.typ * string (* Dotlseg(coo,e1,e2,k,h,c): list box from e1 to e2 at coordinate coo and color c*) | Dotlseg of coordinate * Sil.exp * Sil.exp * Sil.lseg_kind * Sil.hpred list * string @@ -294,7 +294,7 @@ let rec dotty_mk_node pe sigma = let n = !dotty_state_count in incr dotty_state_count; let do_hpred_lambda exp_color = function - | (Sil.Hpointsto (e, Sil.Earray (e', l, _), Sil.Sizeof (Sil.Tarray(t, _), _, _)), lambda) -> + | (Sil.Hpointsto (e, Sil.Earray (e', l, _), Sil.Sizeof (Sil.Tarray (t, _), _, _)), lambda) -> incr dotty_state_count; (* increment once more n+1 is the box for the array *) let e_color_str = color_to_str (exp_color e) in let e_color_str'= color_to_str (exp_color e') in @@ -1221,13 +1221,13 @@ let rec compute_target_nodes_from_sexp nodes se prop field_lab = compute_target_nodes_from_sexp nodes se2 prop (Ident.fieldname_to_string fn) @ compute_target_nodes_from_sexp nodes (Sil.Estruct (l', inst)) prop "" ) - | Sil.Earray(size, lie, inst) -> + | Sil.Earray (len, lie, inst) -> (match lie with | [] -> [] | (idx, se2):: l' -> let lab ="["^exp_to_xml_string idx^"]" in compute_target_nodes_from_sexp nodes se2 prop lab @ - compute_target_nodes_from_sexp nodes (Sil.Earray(size, l', inst)) prop "" + compute_target_nodes_from_sexp nodes (Sil.Earray (len, l', inst)) prop "" ) @@ -1291,9 +1291,9 @@ let rec pointsto_contents_to_xml (co: Sil.strexp) : Io_infer.Xml.node = | Sil.Estruct (fel, _) -> let f (fld, exp) = Io_infer.Xml.create_tree "struct-field" [("id", Ident.fieldname_to_string fld)] [(pointsto_contents_to_xml exp)] in Io_infer.Xml.create_tree "struct" [] (IList.map f fel) - | Sil.Earray (size, nel, _) -> + | Sil.Earray (len, nel, _) -> let f (e, se) = Io_infer.Xml.create_tree "array-element" [("index", exp_to_xml_string e)] [pointsto_contents_to_xml se] in - Io_infer.Xml.create_tree "array" [("size", exp_to_xml_string size)] (IList.map f nel) + Io_infer.Xml.create_tree "array" [("size", exp_to_xml_string len)] (IList.map f nel) (* Convert an atom to xml in a light version. Namely, the expressions are not fully blown-up into *) (* xml tree but visualized as strings *) diff --git a/infer/src/backend/iList.ml b/infer/src/backend/iList.ml index c9b8e8bc9..0c4ddbca9 100644 --- a/infer/src/backend/iList.ml +++ b/infer/src/backend/iList.ml @@ -29,8 +29,8 @@ let stable_sort = List.stable_sort let tl = List.tl let rec last = function - | [] -> invalid_arg "IList.last" - | [x] -> x + | [] -> None + | [x] -> Some x | _ :: xs -> last xs (** tail-recursive variant of List.fold_right *) diff --git a/infer/src/backend/iList.mli b/infer/src/backend/iList.mli index c2a241d75..b054cd329 100644 --- a/infer/src/backend/iList.mli +++ b/infer/src/backend/iList.mli @@ -64,8 +64,8 @@ val split : ('a * 'b) list -> 'a list * 'b list val stable_sort : ('a -> 'a -> int) -> 'a list -> 'a list val tl : 'a list -> 'a list -(** last element, raises invalid_arg if empty *) -val last : 'a list -> 'a +(** last element, if any *) +val last : 'a list -> 'a option (* Drops the first n elements from a list. *) val drop_first : int -> 'a list -> 'a list diff --git a/infer/src/backend/match.ml b/infer/src/backend/match.ml index 3b8b4b688..08b0545cb 100644 --- a/infer/src/backend/match.ml +++ b/infer/src/backend/match.ml @@ -101,8 +101,8 @@ let rec strexp_match sexp1 sub vars sexp2 : (Sil.subst * Ident.t list) option = fsel_match fsel1 sub vars fsel2 | Sil.Estruct _, _ | _, Sil.Estruct _ -> None - | Sil.Earray (size1, isel1, _), Sil.Earray (size2, isel2, _) -> - (match exp_match size1 sub vars size2 with + | Sil.Earray (len1, isel1, _), Sil.Earray (len2, isel2, _) -> + (match exp_match len1 sub vars len2 with | Some (sub', vars') -> isel_match isel1 sub' vars' isel2 | None -> None) @@ -497,8 +497,8 @@ let rec generate_todos_from_strexp mode todos sexp1 sexp2 = else generate_todos_from_fel mode todos fel1 fel2 | Sil.Estruct _, _ -> None - | Sil.Earray (size1, iel1, _), Sil.Earray (size2, iel2, _) -> - if (not (Sil.exp_equal size1 size2) || IList.length iel1 <> IList.length iel2) + | Sil.Earray (len1, iel1, _), Sil.Earray (len2, iel2, _) -> + if (not (Sil.exp_equal len1 len2) || IList.length iel1 <> IList.length iel2) then None else generate_todos_from_iel mode todos iel1 iel2 | Sil.Earray _, _ -> diff --git a/infer/src/backend/modelBuiltins.ml b/infer/src/backend/modelBuiltins.ml index 55bc82eac..f53fbd29f 100644 --- a/infer/src/backend/modelBuiltins.ml +++ b/infer/src/backend/modelBuiltins.ml @@ -28,24 +28,24 @@ let execute___builtin_va_arg { Builtin.pdesc; tenv; prop_; path; ret_ids; args; SymExec.instrs ~mask_errors:true tenv pdesc [instr'] [(prop_, path)] | _ -> raise (Exceptions.Wrong_argument_number __POS__) -let mk_empty_array size = - Sil.Earray (size, [], Sil.inst_none) +let mk_empty_array len = + Sil.Earray (len, [], Sil.inst_none) (* Make a rearranged array. As it is rearranged when it appears in a precondition it requires that the function is called with the array allocated. If not infer return a null pointer deref *) -let mk_empty_array_rearranged size = - Sil.Earray (size, [], Sil.inst_rearrange true (State.get_loc ()) (State.get_path_pos ())) +let mk_empty_array_rearranged len = + Sil.Earray (len, [], Sil.inst_rearrange true (State.get_loc ()) (State.get_path_pos ())) let extract_array_type typ = if (!Config.curr_language = Config.Java) then match typ with - | Sil.Tptr ( Sil.Tarray (typ', _), _) -> Some typ' + | Sil.Tptr (Sil.Tarray _ as arr, _) -> Some arr | _ -> None else match typ with - | Sil.Tptr (typ', _) | Sil.Tarray (typ', _) -> - Some typ' + | Sil.Tarray _ as arr -> Some arr + | Sil.Tptr (elt, _) -> Some (Sil.Tarray (elt, None)) | _ -> None (** Return a result from a procedure call. *) @@ -54,8 +54,8 @@ let return_result e prop ret_ids = | [ret_id] -> Prop.conjoin_eq e (Sil.Var ret_id) prop | _ -> prop -(* Add an array of typ pointed to by lexp to prop_ if it doesnt exist alread*) -(* Return the new prop and the array size *) +(* Add an array of typ pointed to by lexp to prop_ if it doesn't already exist *) +(* Return the new prop and the array length *) (* Return None if it fails to add the array *) let add_array_to_prop pdesc prop_ lexp typ = let pname = Cfg.Procdesc.get_proc_name pdesc in @@ -66,24 +66,21 @@ let add_array_to_prop pdesc prop_ lexp typ = | Sil.Hpointsto(e, _, _) -> Sil.exp_equal e n_lexp | _ -> false) (Prop.get_sigma prop) in match hpred with - | Sil.Hpointsto(_, Sil.Earray(size, _, _), _) -> - Some (size, prop) + | Sil.Hpointsto(_, Sil.Earray (len, _, _), _) -> + Some (len, prop) | _ -> None (* e points to something but not an array *) with Not_found -> (* e is not allocated, so we can add the array *) - let otyp' = (extract_array_type typ) in - match otyp' with - | Some typ' -> - let size = Sil.Var(Ident.create_fresh Ident.kfootprint) in - let s = mk_empty_array_rearranged size in - let hpred = - Prop.mk_ptsto n_lexp s - (Sil.Sizeof (Sil.Tarray (typ', size), None, Sil.Subtype.exact)) in - let sigma = Prop.get_sigma prop in - let sigma_fp = Prop.get_sigma_footprint prop in - let prop'= Prop.replace_sigma (hpred:: sigma) prop in - let prop''= Prop.replace_sigma_footprint (hpred:: sigma_fp) prop' in - let prop''= Prop.normalize prop'' in - Some (size, prop'') + match extract_array_type typ with + | Some arr_typ -> + let len = Sil.Var (Ident.create_fresh Ident.kfootprint) in + let s = mk_empty_array_rearranged len in + let hpred = Prop.mk_ptsto n_lexp s (Sil.Sizeof (arr_typ, Some len, Sil.Subtype.exact)) in + let sigma = Prop.get_sigma prop in + let sigma_fp = Prop.get_sigma_footprint prop in + let prop'= Prop.replace_sigma (hpred:: sigma) prop in + let prop''= Prop.replace_sigma_footprint (hpred:: sigma_fp) prop' in + let prop''= Prop.normalize prop'' in + Some (len, prop'') | _ -> None end @@ -97,31 +94,31 @@ let execute___require_allocated_array { Builtin.pdesc; prop_; path; ret_ids; arg | Some (_, prop) -> [(prop, path)]) | _ -> raise (Exceptions.Wrong_argument_number __POS__) -let execute___get_array_size { Builtin.pdesc; prop_; path; ret_ids; args; } +let execute___get_array_length { Builtin.pdesc; prop_; path; ret_ids; args; } : Builtin.ret_typ = match args with | [(lexp, typ)] when IList.length ret_ids <= 1 -> (match add_array_to_prop pdesc prop_ lexp typ with | None -> [] - | Some (size, prop) -> [(return_result size prop ret_ids, path)]) + | Some (len, prop) -> [(return_result len prop ret_ids, path)]) | _ -> raise (Exceptions.Wrong_argument_number __POS__) -let execute___set_array_size { Builtin.pdesc; prop_; path; ret_ids; args; } +let execute___set_array_length { Builtin.pdesc; prop_; path; ret_ids; args; } : Builtin.ret_typ = match args, ret_ids with - | [(lexp, typ); (size, _)], []-> + | [(lexp, typ); (len, _)], []-> (match add_array_to_prop pdesc prop_ lexp typ with | None -> [] | Some (_, prop_a) -> (* Invariant: prop_a has an array pointed to by lexp *) let pname = Cfg.Procdesc.get_proc_name pdesc in let n_lexp, prop__ = check_arith_norm_exp pname lexp prop_a in - let n_size, prop = check_arith_norm_exp pname size prop__ in + let n_len, prop = check_arith_norm_exp pname len prop__ in let hpred, sigma' = IList.partition (function | Sil.Hpointsto(e, _, _) -> Sil.exp_equal e n_lexp | _ -> false) (Prop.get_sigma prop) in (match hpred with | [Sil.Hpointsto(e, Sil.Earray(_, esel, inst), t)] -> - let hpred' = Sil.Hpointsto (e, Sil.Earray (n_size, esel, inst), t) in + let hpred' = Sil.Hpointsto (e, Sil.Earray (n_len, esel, inst), t) in let prop' = Prop.replace_sigma (hpred':: sigma') prop in [(Prop.normalize prop', path)] | _ -> [])) (* by construction of prop_a this case is impossible *) @@ -162,8 +159,8 @@ let create_type tenv n_lexp typ prop = let hpred = Prop.mk_ptsto n_lexp sexp texp in Some hpred | Sil.Tarray _ -> - let size = Sil.Var(Ident.create_fresh Ident.kfootprint) in - let sexp = mk_empty_array size in + let len = Sil.Var (Ident.create_fresh Ident.kfootprint) in + let sexp = mk_empty_array len in let texp = Sil.Sizeof (typ, None, Sil.Subtype.subtypes) in let hpred = Prop.mk_ptsto n_lexp sexp texp in Some hpred @@ -763,11 +760,9 @@ let execute_alloc mk can_return_null | Sil.Const _ | Sil.Cast _ | Sil.Lvar _ | Sil.Lfield _ | Sil.Lindex _ -> e | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, _), Some len, _) when Sil.ikind_is_char ik -> evaluate_char_sizeof len - | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, len), None, _) when Sil.ikind_is_char ik -> - evaluate_char_sizeof len + | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, Some len), None, _) when Sil.ikind_is_char ik -> + evaluate_char_sizeof (Sil.Const (Sil.Cint len)) | Sil.Sizeof _ -> e in - let handle_sizeof_exp len = - Sil.Sizeof (Sil.Tarray (Sil.Tint Sil.IChar, len), Some len, Sil.Subtype.exact) in let size_exp, procname = match args with | [(Sil.Sizeof (Sil.Tstruct @@ -790,7 +785,8 @@ let execute_alloc mk can_return_null let n_size_exp, prop = check_arith_norm_exp pname size_exp prop_ in let n_size_exp' = evaluate_char_sizeof n_size_exp in Prop.exp_normalize_prop prop n_size_exp', prop in - let cnt_te = handle_sizeof_exp size_exp' in + let cnt_te = + Sil.Sizeof (Sil.Tarray (Sil.Tint Sil.IChar, None), Some size_exp', Sil.Subtype.exact) in let id_new = Ident.create_fresh Ident.kprimed in let exp_new = Sil.Var id_new in let ptsto_new = @@ -989,9 +985,9 @@ let __delete_array = Builtin.register let __exit = Builtin.register (* _exit from C library *) "_exit" execute_exit -let __get_array_size = Builtin.register - (* return the size of the array passed as a parameter *) - "__get_array_size" execute___get_array_size +let __get_array_length = Builtin.register + (* return the length of the array passed as a parameter *) + "__get_array_length" execute___get_array_length let __require_allocated_array = Builtin.register (* require the parameter to point to an allocated array *) "__require_allocated_array" execute___require_allocated_array @@ -1053,9 +1049,9 @@ let __placement_new = Builtin.register let _ = Builtin.register (* print a value as seen by the engine *) "__print_value" execute___print_value -let __set_array_size = Builtin.register - (* set the size of the array passed as a parameter *) - "__set_array_size" execute___set_array_size +let __set_array_length = Builtin.register + (* set the length of the array passed as a parameter *) + "__set_array_length" execute___set_array_length let __set_autorelease_attribute = Builtin.register (* set the attribute of the parameter as autorelease *) "__set_autorelease_attribute" execute___set_autorelease_attribute diff --git a/infer/src/backend/modelBuiltins.mli b/infer/src/backend/modelBuiltins.mli index 991d638d1..e4109e0d6 100644 --- a/infer/src/backend/modelBuiltins.mli +++ b/infer/src/backend/modelBuiltins.mli @@ -15,7 +15,7 @@ val __assert_fail : Procname.t val __delete : Procname.t val __delete_array : Procname.t val __exit : Procname.t -val __get_array_size : Procname.t +val __get_array_length : Procname.t val __get_type_of : Procname.t val __infer_fail : Procname.t val __instanceof : Procname.t (** [__instanceof(val,typ)] implements java's [val instanceof typ] *) @@ -26,7 +26,7 @@ val __new : Procname.t val __new_array : Procname.t val __objc_alloc : Procname.t val __objc_alloc_no_fail : Procname.t -val __set_array_size : Procname.t +val __set_array_length : Procname.t val __unwrap_exception : Procname.t val __set_file_attribute : Procname.t val __set_mem_attribute : Procname.t diff --git a/infer/src/backend/prop.ml b/infer/src/backend/prop.ml index 21e352862..e2893645e 100644 --- a/infer/src/backend/prop.ml +++ b/infer/src/backend/prop.ml @@ -456,10 +456,12 @@ let sym_eval abs e = Sil.Const (Sil.Cclosure { c with captured_vars; }) | Sil.Const _ -> e - | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, l), None, _) | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, _), Some l, _) - when Sil.ikind_is_char ik && !Config.curr_language <> Config.Java -> + when Sil.ikind_is_char ik && !Config.curr_language = Config.Clang -> eval l + | Sil.Sizeof (Sil.Tarray (Sil.Tint ik, Some l), _, _) + when Sil.ikind_is_char ik && !Config.curr_language = Config.Clang -> + Sil.Const (Sil.Cint l) | Sil.Sizeof _ -> e | Sil.Cast (_, e1) -> @@ -592,53 +594,31 @@ let sym_eval abs e = (* progress: convert inner +I to +A *) let e2' = Sil.BinOp (Sil.PlusA, e12, e2) in eval (Sil.BinOp (Sil.PlusPI, e11, e2')) - | Sil.BinOp - (Sil.PlusA, - (Sil.Sizeof (Sil.Tstruct struct_typ, None, _) as e1), - e2) -> - (* pattern for extensible structs given a struct declatead as struct s { ... t arr[n] ... }, - allocation pattern malloc(sizeof(struct s) + k * siezof(t)) turn it into - struct s { ... t arr[n + k] ... } *) - let e1' = eval e1 in - let e2' = eval e2 in - let instance_fields = struct_typ.Sil.instance_fields in - (match IList.rev instance_fields, e2' with - (fname, Sil.Tarray (typ, size), _) :: ltfa, - Sil.BinOp(Sil.Mult, num_elem, Sil.Sizeof (texp, None, st)) - when instance_fields != [] && Sil.typ_equal typ texp -> - let size' = Sil.BinOp(Sil.PlusA, size, num_elem) in - let ltfa' = (fname, Sil.Tarray(typ, size'), Sil.item_annotation_empty) :: ltfa in - let struct_typ' = - { struct_typ with Sil.instance_fields = IList.rev ltfa' } in - Sil.Sizeof (Sil.Tstruct struct_typ', None, st) - | _ -> Sil.BinOp(Sil.PlusA, e1', e2')) | Sil.BinOp (Sil.PlusA as oplus, e1, e2) | Sil.BinOp (Sil.PlusPI as oplus, e1, e2) -> let e1' = eval e1 in let e2' = eval e2 in let isPlusA = oplus = Sil.PlusA in let ominus = if isPlusA then Sil.MinusA else Sil.MinusPI in - let (+++) x y = match y with - | Sil.Const (Sil.Cint i) when Sil.Int.iszero i -> x + let (+++) x y = match x, y with + | _, Sil.Const (Sil.Cint i) when Sil.Int.iszero i -> x + | Sil.Const (Sil.Cint i), Sil.Const (Sil.Cint j) -> Sil.Const (Sil.Cint (Sil.Int.add i j)) | _ -> Sil.BinOp (oplus, x, y) in - let (---) x y = match y with - | Sil.Const (Sil.Cint i) when Sil.Int.iszero i -> x + let (---) x y = match x, y with + | _, Sil.Const (Sil.Cint i) when Sil.Int.iszero i -> x + | Sil.Const (Sil.Cint i), Sil.Const (Sil.Cint j) -> Sil.Const (Sil.Cint (Sil.Int.sub i j)) | _ -> Sil.BinOp (ominus, x, y) in + (* test if the extensible array at the end of [typ] has elements of type [elt] *) + let extensible_array_element_typ_equal elt typ = + Option.map_default (Sil.typ_equal elt) false (Sil.get_extensible_array_element_typ typ) in begin match e1', e2' with - | Sil.Sizeof (typ, Some len1, st), - Sil.BinOp (Sil.Mult, len2, Sil.Sizeof (elt, None, _)) - when isPlusA - && (match typ with - | Sil.Tarray (elt2, _) -> - Sil.typ_equal elt elt2 - | Sil.Tstruct {instance_fields= _::_ as flds} -> - Sil.typ_equal elt (snd3 (IList.last flds)) - | _ -> - false) -> - (* pattern for extensible structs: - sizeof(struct s {... t[l]}) + k * sizeof(elt)) = sizeof(struct s {... t[l + k]}) *) - Sil.Sizeof (typ, Some (len1 +++ len2), st) + (* pattern for arrays and extensible structs: + sizeof(struct s {... t[l]}) + k * sizeof(t)) = sizeof(struct s {... t[l + k]}) *) + | Sil.Sizeof (typ, len1_opt, st), Sil.BinOp (Sil.Mult, len2, Sil.Sizeof (elt, None, _)) + when isPlusA && (extensible_array_element_typ_equal elt typ) -> + let len = match len1_opt with Some len1 -> len1 +++ len2 | None -> len2 in + Sil.Sizeof (typ, Some len, st) | Sil.Const c, _ when iszero_int_float c -> e2' | _, Sil.Const c when iszero_int_float c -> @@ -750,10 +730,13 @@ let sym_eval abs e = | Sil.Const (Sil.Cfloat v), Sil.Const (Sil.Cfloat w) -> Sil.exp_float (v /.w) | Sil.Sizeof (Sil.Tarray (elt, _), Some len, _), Sil.Sizeof (elt2, None, _) - | Sil.Sizeof (Sil.Tarray (elt, len), None, _), Sil.Sizeof (elt2, None, _) (* pattern: sizeof(elt[len]) / sizeof(elt) = len *) when Sil.typ_equal elt elt2 -> len + | Sil.Sizeof (Sil.Tarray (elt, Some len), None, _), Sil.Sizeof (elt2, None, _) + (* pattern: sizeof(elt[len]) / sizeof(elt) = len *) + when Sil.typ_equal elt elt2 -> + Sil.Const (Sil.Cint len) | _ -> if abs then Sil.exp_get_undefined false else Sil.BinOp (Sil.Div, e1', e2') end @@ -852,65 +835,10 @@ let exp_normalize sub exp = if !Config.abs_val >= 1 then sym_eval true exp' else sym_eval false exp' -let rec texp_normalize sub exp = match exp with - | Sil.Sizeof (typ, len, st) -> - Sil.Sizeof (typ_normalize sub typ, Option.map (exp_normalize sub) len, st) +let texp_normalize sub exp = match exp with + | Sil.Sizeof (typ, len, st) -> Sil.Sizeof (typ, Option.map (exp_normalize sub) len, st) | _ -> exp_normalize sub exp -(* NOTE: usage of == operator in flds_norm and typ_normalize is intended*) -(* to decrease pressure on ocaml's GC and not allocate new objects if typ_normalize*) -(* doesn't change anything in structure of the type *) -and flds_norm sub fields = - let fld_norm ((f, t, a) as field) = - let t' = typ_normalize sub t in - if t' == t then - field - else - (f, t', a) in - - let rec flds_norm_aux fields = match fields with - | [] -> fields - | field :: rest -> - let rest' = flds_norm_aux rest in - let field' = fld_norm field in - if field == field' && rest == rest' then - fields - else - field' :: rest' in - flds_norm_aux fields - -and typ_normalize sub typ = match typ with - | Sil.Tvar _ - | Sil.Tint _ - | Sil.Tfloat _ - | Sil.Tvoid - | Sil.Tfun _ -> - typ - | Sil.Tptr (t, pk) -> - let t' = typ_normalize sub t in - if t == t' then - typ - else - Sil.Tptr (t', pk) - | Sil.Tstruct struct_typ -> - let instance_fields = struct_typ.Sil.instance_fields in - let instance_fields' = flds_norm sub instance_fields in - let static_fields = struct_typ.Sil.static_fields in - let static_fields' = flds_norm sub static_fields in - if instance_fields == instance_fields' && static_fields == static_fields' then - typ - else - Sil.Tstruct - { struct_typ with - Sil.instance_fields = instance_fields'; - static_fields = static_fields'; - } - | Sil.Tarray (t, e) -> - (* this case is not optimized for less GC allocations since it requires*) - (* to make exp_normalize GC-friendly as well. Profiling showed that it's fine*) - (* to keep this code not optimized *) - Sil.Tarray (typ_normalize sub t, exp_normalize sub e) - let run_with_abs_val_eq_zero f = let abs_val_old = !Config.abs_val in Config.abs_val := 0; @@ -1136,12 +1064,12 @@ let rec strexp_normalize sub se = let fld_cnts'' = IList.sort Sil.fld_strexp_compare fld_cnts' in Sil.Estruct (fld_cnts'', inst) end - | Sil.Earray (size, idx_cnts, inst) -> + | Sil.Earray (len, idx_cnts, inst) -> begin - let size' = exp_normalize_noabs sub size in + let len' = exp_normalize_noabs sub len in match idx_cnts with | [] -> - if Sil.exp_equal size size' then se else Sil.Earray (size', idx_cnts, inst) + if Sil.exp_equal len len' then se else Sil.Earray (len', idx_cnts, inst) | _ -> let idx_cnts' = IList.map (fun (idx, cnt) -> @@ -1149,7 +1077,7 @@ let rec strexp_normalize sub se = idx', strexp_normalize sub cnt) idx_cnts in let idx_cnts'' = IList.sort Sil.exp_strexp_compare idx_cnts' in - Sil.Earray (size', idx_cnts'', inst) + Sil.Earray (len', idx_cnts'', inst) end (** create a strexp of the given type, populating the structures if [expand_structs] is true *) @@ -1184,8 +1112,11 @@ let rec create_strexp_of_type tenvo struct_init_mode typ len inst = let flds, _ = IList.fold_right f instance_fields ([], len) in Sil.Estruct (flds, inst) ) - | Sil.Tarray (_, size), None -> - Sil.Earray (size, [], inst) + | Sil.Tarray (_, len_opt), None -> + let len = match len_opt with + | None -> Sil.exp_get_undefined false + | Some len -> Sil.Const (Sil.Cint len) in + Sil.Earray (len, [], inst) | Sil.Tarray _, Some len -> Sil.Earray (len, [], inst) | Sil.Tvar _, _ @@ -1216,8 +1147,8 @@ let mk_ptsto_exp tenvo struct_init_mode (exp, te, expo) inst : Sil.hpred = mk_ptsto exp strexp te let replace_array_contents hpred esel = match hpred with - | Sil.Hpointsto (root, Sil.Earray (size, [], inst), te) -> - Sil.Hpointsto (root, Sil.Earray (size, esel, inst), te) + | Sil.Hpointsto (root, Sil.Earray (len, [], inst), te) -> + Sil.Hpointsto (root, Sil.Earray (len, esel, inst), te) | _ -> assert false let rec hpred_normalize sub hpred = @@ -2345,39 +2276,20 @@ let rec exp_captured_ren ren = function | Sil.Var id -> Sil.Var (ident_captured_ren ren id) | Sil.Const (Sil.Cexn e) -> Sil.Const (Sil.Cexn (exp_captured_ren ren e)) | Sil.Const _ as e -> e - | Sil.Sizeof (t, len, st) -> - Sil.Sizeof (typ_captured_ren ren t, Option.map (exp_captured_ren ren) len, st) + | Sil.Sizeof (t, len, st) -> Sil.Sizeof (t, Option.map (exp_captured_ren ren) len, st) | Sil.Cast (t, e) -> Sil.Cast (t, exp_captured_ren ren e) - | Sil.UnOp (op, e, topt) -> - let topt' = match topt with - | Some t -> Some (typ_captured_ren ren t) - | None -> None in - Sil.UnOp (op, exp_captured_ren ren e, topt') + | Sil.UnOp (op, e, topt) -> Sil.UnOp (op, exp_captured_ren ren e, topt) | Sil.BinOp (op, e1, e2) -> let e1' = exp_captured_ren ren e1 in let e2' = exp_captured_ren ren e2 in Sil.BinOp (op, e1', e2') | Sil.Lvar id -> Sil.Lvar id - | Sil.Lfield (e, fld, typ) -> Sil.Lfield (exp_captured_ren ren e, fld, typ_captured_ren ren typ) + | Sil.Lfield (e, fld, typ) -> Sil.Lfield (exp_captured_ren ren e, fld, typ) | Sil.Lindex (e1, e2) -> let e1' = exp_captured_ren ren e1 in let e2' = exp_captured_ren ren e2 in Sil.Lindex(e1', e2') -(* Apply a renaming function to a type *) -and typ_captured_ren ren typ = match typ with - | Sil.Tvar _ - | Sil.Tint _ - | Sil.Tfloat _ - | Sil.Tvoid - | Sil.Tstruct _ - | Sil.Tfun _ -> - typ - | Sil.Tptr (t', pk) -> - Sil.Tptr (typ_captured_ren ren t', pk) - | Sil.Tarray (t, e) -> - Sil.Tarray (typ_captured_ren ren t, exp_captured_ren ren e) - let atom_captured_ren ren = function | Sil.Aeq (e1, e2) -> Sil.Aeq (exp_captured_ren ren e1, exp_captured_ren ren e2) @@ -2390,12 +2302,12 @@ let rec strexp_captured_ren ren = function | Sil.Estruct (fld_se_list, inst) -> let f (fld, se) = (fld, strexp_captured_ren ren se) in Sil.Estruct (IList.map f fld_se_list, inst) - | Sil.Earray (size, idx_se_list, inst) -> + | Sil.Earray (len, idx_se_list, inst) -> let f (idx, se) = let idx' = exp_captured_ren ren idx in (idx', strexp_captured_ren ren se) in - let size' = exp_captured_ren ren size in - Sil.Earray (size', IList.map f idx_se_list, inst) + let len' = exp_captured_ren ren len in + Sil.Earray (len', IList.map f idx_se_list, inst) and hpred_captured_ren ren = function | Sil.Hpointsto (base, se, te) -> diff --git a/infer/src/backend/prover.ml b/infer/src/backend/prover.ml index 50477a07d..a2ec12868 100644 --- a/infer/src/backend/prover.ml +++ b/infer/src/backend/prover.ml @@ -380,8 +380,8 @@ end = struct | Sil.Eexp _ -> () | Sil.Estruct (fsel, _) -> IList.iter (fun (_, se) -> strexp_extract se) fsel - | Sil.Earray (size, isel, _) -> - add_lt_minus1_e size; + | Sil.Earray (len, isel, _) -> + add_lt_minus1_e len; IList.iter (fun (idx, se) -> add_lt_minus1_e idx; strexp_extract se) isel in @@ -909,7 +909,7 @@ module ProverState : sig val checks : check list ref type bounds_check = (** type for array bounds checks *) - | BCsize_imply of Sil.exp * Sil.exp * Sil.exp list (** coming from array_size_imply *) + | BClen_imply of Sil.exp * Sil.exp * Sil.exp list (** coming from array_len_imply *) | BCfrom_pre of Sil.atom (** coming implicitly from preconditions *) val add_bounds_check : bounds_check -> unit @@ -934,12 +934,12 @@ module ProverState : sig val d_implication_error : string * (Sil.subst * Sil.subst) * exc_body -> unit end = struct type bounds_check = - | BCsize_imply of Sil.exp * Sil.exp * Sil.exp list + | BClen_imply of Sil.exp * Sil.exp * Sil.exp list | BCfrom_pre of Sil.atom let implication_lhs = ref Prop.prop_emp let implication_rhs = ref (Prop.expose Prop.prop_emp) - let fav_in_array_size = ref (Sil.fav_new ()) (* free variables in array size position *) + let fav_in_array_len = ref (Sil.fav_new ()) (* free variables in array len position *) let bounds_checks = ref [] (* delayed bounds check for arrays *) let frame_fld = ref [] let missing_fld = ref [] @@ -949,12 +949,12 @@ end = struct let missing_typ = ref [] let checks = ref [] - (** free vars in array size position in current part of prop *) - let prop_fav_size prop = + (** free vars in array len position in current strexp part of prop *) + let prop_fav_len prop = let fav = Sil.fav_new () in let do_hpred = function - | Sil.Hpointsto (_, Sil.Earray (Sil.Var _ as size, _, _), _) -> - Sil.exp_fav_add fav size + | Sil.Hpointsto (_, Sil.Earray (Sil.Var _ as len, _, _), _) -> + Sil.exp_fav_add fav len | _ -> () in IList.iter do_hpred (Prop.get_sigma prop); fav @@ -963,7 +963,7 @@ end = struct checks := []; implication_lhs := lhs; implication_rhs := rhs; - fav_in_array_size := prop_fav_size rhs; + fav_in_array_len := prop_fav_len rhs; bounds_checks := []; frame_fld := []; frame_typ := []; @@ -993,11 +993,12 @@ end = struct let add_missing_sigma sigma = missing_sigma := sigma @ !missing_sigma - (** atom considered array bounds check if it contains vars present in array size position in the pre *) + (** atom considered array bounds check if it contains vars present in array length position in the + pre *) let atom_is_array_bounds_check atom = let fav_a = Sil.atom_fav atom in Prop.atom_is_inequality atom && - Sil.fav_exists fav_a (fun a -> Sil.fav_mem !fav_in_array_size a) + Sil.fav_exists fav_a (fun a -> Sil.fav_mem !fav_in_array_len a) let get_bounds_checks () = !bounds_checks let get_frame_fld () = !frame_fld @@ -1213,18 +1214,18 @@ let path_to_id path = | None -> Ident.create_fresh Ident.kfootprint | Some s -> Ident.create_path s -(** Implication for the size of arrays *) -let array_size_imply calc_missing subs size1 size2 indices2 = - match size1, size2 with +(** Implication for the length of arrays *) +let array_len_imply calc_missing subs len1 len2 indices2 = + match len1, len2 with | _, Sil.Var _ | _, Sil.BinOp (Sil.PlusA, Sil.Var _, _) | _, Sil.BinOp (Sil.PlusA, _, Sil.Var _) | Sil.BinOp (Sil.Mult, _, _), _ -> - (try exp_imply calc_missing subs size1 size2 with + (try exp_imply calc_missing subs len1 len2 with | IMPL_EXC (s, subs', x) -> - raise (IMPL_EXC ("array size:" ^ s, subs', x))) + raise (IMPL_EXC ("array len:" ^ s, subs', x))) | _ -> - ProverState.add_bounds_check (ProverState.BCsize_imply (size1, size2, indices2)); + ProverState.add_bounds_check (ProverState.BClen_imply (len1, len2, indices2)); subs (** Extend [sub1] and [sub2] to witnesses that each instance of @@ -1252,18 +1253,18 @@ let rec sexp_imply source calc_index_frame calc_missing subs se1 se2 typ2 : subs d_impl_err ("sexp_imply not implemented", subs, (EXC_FALSE_SEXPS (se1, se2))); raise (Exceptions.Abduction_case_not_implemented __POS__) end - | Sil.Earray (size1, esel1, inst1), Sil.Earray (size2, esel2, _) -> + | Sil.Earray (len1, esel1, inst1), Sil.Earray (len2, esel2, _) -> let indices2 = IList.map fst esel2 in - let subs' = array_size_imply calc_missing subs size1 size2 indices2 in + let subs' = array_len_imply calc_missing subs len1 len2 indices2 in let subs'', index_frame, index_missing = array_imply source calc_index_frame calc_missing subs' esel1 esel2 typ2 in let index_frame_opt = if index_frame != [] - then Some (Sil.Earray (size1, index_frame, inst1)) + then Some (Sil.Earray (len1, index_frame, inst1)) else None in let index_missing_opt = if index_missing != [] && (Config.allow_missing_index_in_proc_call || !Config.footprint) - then Some (Sil.Earray (size1, index_missing, inst1)) + then Some (Sil.Earray (len1, index_missing, inst1)) else None in subs'', index_frame_opt, index_missing_opt | Sil.Eexp (_, inst), Sil.Estruct (fsel, inst') -> @@ -1272,13 +1273,17 @@ let rec sexp_imply source calc_index_frame calc_missing subs se1 se2 typ2 : subs let g (f, _) = (f, Sil.Eexp (Sil.Var (Ident.create_fresh Ident.knormal), inst)) in IList.map g fsel in sexp_imply source calc_index_frame calc_missing subs (Sil.Estruct (fsel', inst')) se2 typ2 - | Sil.Eexp _, Sil.Earray (size, _, inst) - | Sil.Estruct _, Sil.Earray (size, _, inst) -> - let se1' = Sil.Earray (size, [(Sil.exp_zero, se1)], inst) in + | Sil.Eexp _, Sil.Earray (len, _, inst) + | Sil.Estruct _, Sil.Earray (len, _, inst) -> + let se1' = Sil.Earray (len, [(Sil.exp_zero, se1)], inst) in sexp_imply source calc_index_frame calc_missing subs se1' se2 typ2 - | Sil.Earray (size, _, _), Sil.Eexp (_, inst) -> - let se2' = Sil.Earray (size, [(Sil.exp_zero, se2)], inst) in - let typ2' = Sil.Tarray (typ2, size) in + | Sil.Earray (len, _, _), Sil.Eexp (_, inst) -> + let se2' = Sil.Earray (len, [(Sil.exp_zero, se2)], inst) in + let typ2' = Sil.Tarray (typ2, None) in + (* In the sexp_imply, struct_imply, array_imply, and sexp_imply_nolhs functions, the typ2 + argument is only used by eventually passing its value to Sil.struct_typ_fld, Sil.Lfield, + Sil.struct_typ_fld, or Sil.array_typ_elem. None of these are sensitive to the length field + of Tarray, so forgetting the length of typ2' here is not a problem. *) sexp_imply source true calc_missing subs se1 se2' typ2' (* calculate index_frame because the rhs is a singleton array *) | _ -> d_impl_err ("sexp_imply not implemented", subs, (EXC_FALSE_SEXPS (se1, se2))); @@ -1442,18 +1447,19 @@ let expand_hpred_pointer calc_index_frame hpred : bool * bool * Sil.hpred = let hpred' = Sil.Hpointsto (e, Sil.Estruct ([(fld, se)], Sil.inst_none), t') in expand true true hpred' | Sil.Hpointsto (Sil.Lindex (e, ind), se, t) -> - let clen = Sil.exp_get_undefined false in let t' = match t with - | Sil.Sizeof (t_, vlen, st) -> - Sil.Sizeof (Sil.Tarray (t_, clen), vlen, st) + | Sil.Sizeof (t_, len, st) -> Sil.Sizeof (Sil.Tarray (t_, None), len, st) | _ -> raise (Failure "expand_hpred_pointer: Unexpected non-sizeof type in Lindex") in - let hpred' = Sil.Hpointsto (e, Sil.Earray (clen, [(ind, se)], Sil.inst_none), t') in + let len = match t' with + | Sil.Sizeof (_, Some len, _) -> len + | _ -> Sil.exp_get_undefined false in + let hpred' = Sil.Hpointsto (e, Sil.Earray (len, [(ind, se)], Sil.inst_none), t') in expand true true hpred' - | Sil.Hpointsto (Sil.BinOp (Sil.PlusPI, e1, e2), Sil.Earray (size, esel, inst), t) -> + | Sil.Hpointsto (Sil.BinOp (Sil.PlusPI, e1, e2), Sil.Earray (len, esel, inst), t) -> let shift_exp e = Sil.BinOp (Sil.PlusA, e, e2) in - let size' = shift_exp size in + let len' = shift_exp len in let esel' = IList.map (fun (e, se) -> (shift_exp e, se)) esel in - let hpred' = Sil.Hpointsto (e1, Sil.Earray (size', esel', inst), t) in + let hpred' = Sil.Hpointsto (e1, Sil.Earray (len', esel', inst), t) in expand true calc_index_frame hpred' | _ -> changed, calc_index_frame, hpred in expand false calc_index_frame hpred @@ -1687,8 +1693,8 @@ let texp_imply tenv subs texp1 texp2 e1 calc_missing = else None, None -(** pre-process implication between a non-array and an array: the non-array is turned into an array of size given by its type - only active in type_size mode *) +(** pre-process implication between a non-array and an array: the non-array is turned into an array + of length given by its type only active in type_size mode *) let sexp_imply_preprocess se1 texp1 se2 = match se1, texp1, se2 with | Sil.Eexp (_, inst), Sil.Sizeof _, Sil.Earray _ when Config.type_size -> let se1' = Sil.Earray (texp1, [(Sil.exp_zero, se1)], inst) in @@ -1941,13 +1947,14 @@ and sigma_imply tenv calc_index_frame calc_missing subs prop1 sigma2 : (subst2 * | _ -> None) | _ -> None in let mk_constant_string_hpred s = (* create an hpred from a constant string *) - let len = Sil.exp_int (Sil.Int.of_int (1 + String.length s)) in + let len = Sil.Int.of_int (1 + String.length s) in let root = Sil.Const (Sil.Cstr s) in let sexp = let index = Sil.exp_int (Sil.Int.of_int (String.length s)) in match !Config.curr_language with | Config.Clang -> - Sil.Earray (len, [(index, Sil.Eexp (Sil.exp_zero, Sil.inst_none))], Sil.inst_none) + Sil.Earray + (Sil.exp_int len, [(index, Sil.Eexp (Sil.exp_zero, Sil.inst_none))], Sil.inst_none) | Config.Java -> let mk_fld_sexp s = let fld = Ident.create_fieldname (Mangled.from_string s) 0 in @@ -1958,7 +1965,7 @@ and sigma_imply tenv calc_index_frame calc_missing subs prop1 sigma2 : (subst2 * let const_string_texp = match !Config.curr_language with | Config.Clang -> - Sil.Sizeof (Sil.Tarray (Sil.Tint Sil.IChar, len), Some len, Sil.Subtype.exact) + Sil.Sizeof (Sil.Tarray (Sil.Tint Sil.IChar, Some len), None, Sil.Subtype.exact) | Config.Java -> let object_type = Typename.TN_csu (Csu.Class Csu.Java, Mangled.from_string "java.lang.String") in @@ -2107,13 +2114,14 @@ let check_array_bounds (sub1, sub2) prop = let lt_ineq = Prop.mk_inequality (Sil.BinOp(Sil.Le, e', e'')) in if check_atom prop lt_ineq then check_failed lt_ineq in let check_bound = function - | ProverState.BCsize_imply (_size1, _size2, _indices2) -> - let size1 = Sil.exp_sub sub1 _size1 in - let size2 = Sil.exp_sub sub2 _size2 in - (* L.d_strln_color Orange "check_bound "; Sil.d_exp size1; L.d_str " "; Sil.d_exp size2; L.d_ln(); *) - let indices_to_check = match size2 with - | _ -> [Sil.BinOp(Sil.PlusA, size2, Sil.exp_minus_one)] (* only check size *) in - IList.iter (fail_if_le size1) indices_to_check + | ProverState.BClen_imply (len1_, len2_, _indices2) -> + let len1 = Sil.exp_sub sub1 len1_ in + let len2 = Sil.exp_sub sub2 len2_ in + (* L.d_strln_color Orange "check_bound "; + Sil.d_exp len1; L.d_str " "; Sil.d_exp len2; L.d_ln(); *) + let indices_to_check = match len2 with + | _ -> [Sil.BinOp(Sil.PlusA, len2, Sil.exp_minus_one)] (* only check len *) in + IList.iter (fail_if_le len1) indices_to_check | ProverState.BCfrom_pre _atom -> let atom_neg = Prop.atom_negate (Sil.atom_sub sub2 _atom) in (* L.d_strln_color Orange "BCFrom_pre"; Sil.d_atom atom_neg; L.d_ln (); *) @@ -2152,8 +2160,10 @@ let check_implication_base pname tenv check_frame_empty calc_missing prop1 prop2 let sigma1' = Prop.sigma_sub sub1 sigma1 in L.d_ln (); let prop_for_impl = prepare_prop_for_implication (sub1, sub2) pi1' sigma1' in - imply_pi calc_missing (sub1, sub2) prop_for_impl pi2_nobcheck; (* only deal with pi2 without bound checks *) - check_array_bounds (sub1, sub2) prop_for_impl; (* handle implicit bound checks, plus those from array_size_imply *) + (* only deal with pi2 without bound checks *) + imply_pi calc_missing (sub1, sub2) prop_for_impl pi2_nobcheck; + (* handle implicit bound checks, plus those from array_len_imply *) + check_array_bounds (sub1, sub2) prop_for_impl; L.d_strln "Result of Abduction"; L.d_increase_indent 1; d_impl (sub1, sub2) (prop1, prop2); L.d_decrease_indent 1; L.d_ln (); L.d_strln"returning TRUE"; diff --git a/infer/src/backend/rearrange.ml b/infer/src/backend/rearrange.ml index 015162294..d518e6500 100644 --- a/infer/src/backend/rearrange.ml +++ b/infer/src/backend/rearrange.ml @@ -28,23 +28,23 @@ let rec list_rev_and_concat l1 l2 = | x1:: l1' -> list_rev_and_concat l1' (x1:: l2) (** Check whether the index is out of bounds. - If the size is - 1, no check is performed. + If the length is - 1, no check is performed. If the index is provably out of bound, a bound error is given. - If the size is a constant and the index is not provably in bound, a warning is given. + If the length is a constant and the index is not provably in bound, a warning is given. *) -let check_bad_index pname p size index loc = - let size_is_constant = match size with +let check_bad_index pname p len index loc = + let len_is_constant = match len with | Sil.Const _ -> true | _ -> false in let index_provably_out_of_bound () = - let index_too_large = Prop.mk_inequality (Sil.BinOp(Sil.Le, size, index)) in - let index_negative = Prop.mk_inequality (Sil.BinOp(Sil.Le, index, Sil.exp_minus_one)) in + let index_too_large = Prop.mk_inequality (Sil.BinOp (Sil.Le, len, index)) in + let index_negative = Prop.mk_inequality (Sil.BinOp (Sil.Le, index, Sil.exp_minus_one)) in (Prover.check_atom p index_too_large) || (Prover.check_atom p index_negative) in let index_provably_in_bound () = - let size_minus_one = Sil.BinOp(Sil.PlusA, size, Sil.exp_minus_one) in - let index_not_too_large = Prop.mk_inequality (Sil.BinOp(Sil.Le, index, size_minus_one)) in + let len_minus_one = Sil.BinOp(Sil.PlusA, len, Sil.exp_minus_one) in + let index_not_too_large = Prop.mk_inequality (Sil.BinOp(Sil.Le, index, len_minus_one)) in let index_nonnegative = Prop.mk_inequality (Sil.BinOp(Sil.Le, Sil.exp_zero, index)) in - Prover.check_zero index || (* index 0 always in bound, even when we know nothing about size *) + Prover.check_zero index || (* index 0 always in bound, even when we know nothing about len *) ((Prover.check_atom p index_not_too_large) && (Prover.check_atom p index_nonnegative)) in let index_has_bounds () = match Prover.get_bounds p index with @@ -55,17 +55,17 @@ let check_bad_index pname p size index loc = | _ -> None in if not (index_provably_in_bound ()) then begin - let size_const_opt = get_const_opt size in + let len_const_opt = get_const_opt len in let index_const_opt = get_const_opt index in if index_provably_out_of_bound () then - let deref_str = Localise.deref_str_array_bound size_const_opt index_const_opt in + let deref_str = Localise.deref_str_array_bound len_const_opt index_const_opt in let exn = Exceptions.Array_out_of_bounds_l1 (Errdesc.explain_array_access deref_str p loc, __POS__) in let pre_opt = State.get_normalized_pre (Abs.abstract_no_symop pname) in Reporting.log_warning pname ~pre: pre_opt exn - else if size_is_constant then - let deref_str = Localise.deref_str_array_bound size_const_opt index_const_opt in + else if len_is_constant then + let deref_str = Localise.deref_str_array_bound len_const_opt index_const_opt in let desc = Errdesc.explain_array_access deref_str p loc in let exn = if index_has_bounds () then Exceptions.Array_out_of_bounds_l2 (desc, __POS__) @@ -75,14 +75,14 @@ let check_bad_index pname p size index loc = end (** Perform bounds checking *) -let bounds_check pname prop size e = +let bounds_check pname prop len e = if Config.trace_rearrange then begin L.d_str "Bounds check index:"; Sil.d_exp e; - L.d_str " size: "; Sil.d_exp size; + L.d_str " len: "; Sil.d_exp len; L.d_ln() end; - check_bad_index pname prop size e + check_bad_index pname prop len e let rec create_struct_values pname tenv orig_prop footprint_part kind max_stamp t (off: Sil.offset list) inst : Sil.atom list * Sil.strexp * Sil.typ = @@ -112,7 +112,8 @@ let rec create_struct_values pname tenv orig_prop footprint_part kind max_stamp create_struct_values pname tenv orig_prop footprint_part kind max_stamp t' off' inst in let se = Sil.Estruct ([(f, se')], inst) in - let replace_typ_of_f (f', t', a') = if Ident.fieldname_equal f f' then (f, res_t', a') else (f', t', a') in + let replace_typ_of_f (f', t', a') = + if Ident.fieldname_equal f f' then (f, res_t', a') else (f', t', a') in let instance_fields' = IList.sort Sil.fld_typ_ann_compare (IList.map replace_typ_of_f instance_fields) in (atoms', se, Sil.Tstruct { struct_typ with Sil.instance_fields = instance_fields'}) @@ -121,25 +122,29 @@ let rec create_struct_values pname tenv orig_prop footprint_part kind max_stamp create_struct_values pname tenv orig_prop footprint_part kind max_stamp t off' inst in let e' = Sil.array_clean_new_index footprint_part e in - let size = Sil.exp_get_undefined false in - let se = Sil.Earray (size, [(e', se')], inst) in - let res_t = Sil.Tarray (res_t', size) in - (Sil.Aeq(e, e'):: atoms', se, res_t) - | Sil.Tarray(_, size),[] -> - ([], Sil.Earray(size, [], inst), t) - | Sil.Tarray(t', size'), (Sil.Off_index e) :: off' -> - bounds_check pname orig_prop size' e (State.get_loc ()); - - let atoms', se', res_t' = - create_struct_values - pname tenv orig_prop footprint_part kind max_stamp t' off' inst in - let e' = Sil.array_clean_new_index footprint_part e in - let se = Sil.Earray(size', [(e', se')], inst) in - let res_t = Sil.Tarray(res_t', size') in - (Sil.Aeq(e, e'):: atoms', se, res_t) - | Sil.Tarray _, (Sil.Off_fld _) :: _ -> - assert false - + let len = Sil.Var (new_id ()) in + let se = Sil.Earray (len, [(e', se')], inst) in + let res_t = Sil.Tarray (res_t', None) in + (Sil.Aeq(e, e') :: atoms', se, res_t) + | Sil.Tarray (t', len_), off -> + let len = match len_ with + | None -> Sil.Var (new_id ()) + | Some len -> Sil.Const (Sil.Cint len) in + (match off with + | [] -> + ([], Sil.Earray (len, [], inst), t) + | (Sil.Off_index e) :: off' -> + bounds_check pname orig_prop len e (State.get_loc ()); + let atoms', se', res_t' = + create_struct_values + pname tenv orig_prop footprint_part kind max_stamp t' off' inst in + let e' = Sil.array_clean_new_index footprint_part e in + let se = Sil.Earray (len, [(e', se')], inst) in + let res_t = Sil.Tarray (res_t', len_) in + (Sil.Aeq(e, e') :: atoms', se, res_t) + | (Sil.Off_fld _) :: _ -> + assert false + ) | Sil.Tint _, [] | Sil.Tfloat _, [] | Sil.Tvoid, [] | Sil.Tfun _, [] | Sil.Tptr _, [] -> let id = new_id () in ([], Sil.Eexp (Sil.Var id, inst), t) @@ -150,14 +155,13 @@ let rec create_struct_values pname tenv orig_prop footprint_part kind max_stamp let t' = match t with | Sil.Tptr(t', _) -> t' | _ -> t in - let size = Sil.Var (new_id ()) in - + let len = Sil.Var (new_id ()) in let atoms', se', res_t' = create_struct_values pname tenv orig_prop footprint_part kind max_stamp t' [] inst in let e' = Sil.array_clean_new_index footprint_part e in - let se = Sil.Earray(size, [(e', se')], inst) in - let res_t = Sil.Tarray(res_t', size) in + let se = Sil.Earray (len, [(e', se')], inst) in + let res_t = Sil.Tarray (res_t', None) in (Sil.Aeq(e, e'):: atoms', se, res_t) | Sil.Tint _, _ | Sil.Tfloat _, _ | Sil.Tvoid, _ | Sil.Tfun _, _ | Sil.Tptr _, _ -> L.d_str "create_struct_values type:"; Sil.d_typ_full t; L.d_str " off: "; Sil.d_offset_list off; L.d_ln(); @@ -185,6 +189,9 @@ let rec create_struct_values pname tenv orig_prop footprint_part kind max_stamp let rec _strexp_extend_values pname tenv orig_prop footprint_part kind max_stamp se typ (off : Sil.offset list) inst = + let new_id () = + incr max_stamp; + Ident.create kind !max_stamp in match off, se, typ with | [], Sil.Eexp _, _ | [], Sil.Estruct _, _ -> @@ -193,7 +200,7 @@ let rec _strexp_extend_values let off_new = Sil.Off_index(Sil.exp_zero):: off in _strexp_extend_values pname tenv orig_prop footprint_part kind max_stamp se typ off_new inst - | (Sil.Off_fld _):: _, Sil.Earray _, Sil.Tarray _ -> + | (Sil.Off_fld _) :: _, Sil.Earray _, Sil.Tarray _ -> let off_new = Sil.Off_index(Sil.exp_zero):: off in _strexp_extend_values pname tenv orig_prop footprint_part kind max_stamp se typ off_new inst @@ -243,18 +250,17 @@ let rec _strexp_extend_values | (Sil.Off_index _):: _, Sil.Eexp _, Sil.Tptr _ | (Sil.Off_index _):: _, Sil.Estruct _, Sil.Tstruct _ -> (* L.d_strln_color Orange "turn into an array"; *) - let size = match se with - | Sil.Eexp (_, Sil.Ialloc) -> Sil.exp_one (* if allocated explicitly, we know size is 1 *) + let len = match se with + | Sil.Eexp (_, Sil.Ialloc) -> Sil.exp_one (* if allocated explicitly, we know len is 1 *) | _ -> if Config.type_size then Sil.exp_one (* Sil.Sizeof (typ, Sil.Subtype.exact) *) - else Sil.exp_get_undefined false in - - let se_new = Sil.Earray(size, [(Sil.exp_zero, se)], inst) in - let typ_new = Sil.Tarray(typ, size) in + else Sil.Var (new_id ()) in + let se_new = Sil.Earray (len, [(Sil.exp_zero, se)], inst) in + let typ_new = Sil.Tarray (typ, None) in _strexp_extend_values pname tenv orig_prop footprint_part kind max_stamp se_new typ_new off inst - | (Sil.Off_index e):: off', Sil.Earray(size, esel, inst_arr), Sil.Tarray(typ', size_for_typ') -> - bounds_check pname orig_prop size e (State.get_loc ()); + | (Sil.Off_index e) :: off', Sil.Earray (len, esel, inst_arr), Sil.Tarray (typ', len_for_typ') -> + bounds_check pname orig_prop len e (State.get_loc ()); begin try let _, se' = IList.find (fun (e', _) -> Sil.exp_equal e e') esel in @@ -264,15 +270,19 @@ let rec _strexp_extend_values let replace acc (res_atoms', res_se', res_typ') = let replace_ise ise = if Sil.exp_equal e (fst ise) then (e, res_se') else ise in let res_esel' = IList.map replace_ise esel in - if (Sil.typ_equal res_typ' typ') || (IList.length res_esel' = 1) - then (res_atoms', Sil.Earray(size, res_esel', inst_arr), Sil.Tarray(res_typ', size_for_typ')) :: acc - else raise (Exceptions.Bad_footprint __POS__) in + if (Sil.typ_equal res_typ' typ') || (IList.length res_esel' = 1) then + ( res_atoms' + , Sil.Earray (len, res_esel', inst_arr) + , Sil.Tarray (res_typ', len_for_typ') ) + :: acc + else + raise (Exceptions.Bad_footprint __POS__) in IList.fold_left replace [] atoms_se_typ_list' with Not_found -> array_case_analysis_index pname tenv orig_prop footprint_part kind max_stamp - size esel - size_for_typ' typ' + len esel + len_for_typ' typ' e off' inst_arr inst end | _, _, _ -> @@ -280,8 +290,8 @@ let rec _strexp_extend_values and array_case_analysis_index pname tenv orig_prop footprint_part kind max_stamp - array_size array_cont - typ_array_size typ_cont + array_len array_cont + typ_array_len typ_cont index off inst_arr inst = let check_sound t' = @@ -290,13 +300,13 @@ and array_case_analysis_index pname tenv orig_prop let index_in_array = IList.exists (fun (i, _) -> Prover.check_equal Prop.prop_emp index i) array_cont in let array_is_full = - match array_size with + match array_len with | Sil.Const (Sil.Cint n') -> Sil.Int.geq (Sil.Int.of_int (IList.length array_cont)) n' | _ -> false in if index_in_array then - let array_default = Sil.Earray(array_size, array_cont, inst_arr) in - let typ_default = Sil.Tarray(typ_cont, typ_array_size) in + let array_default = Sil.Earray (array_len, array_cont, inst_arr) in + let typ_default = Sil.Tarray (typ_cont, typ_array_len) in [([], array_default, typ_default)] else if !Config.footprint then begin let atoms, elem_se, elem_typ = @@ -304,8 +314,8 @@ and array_case_analysis_index pname tenv orig_prop pname tenv orig_prop footprint_part kind max_stamp typ_cont off inst in check_sound elem_typ; let cont_new = IList.sort Sil.exp_strexp_compare ((index, elem_se):: array_cont) in - let array_new = Sil.Earray(array_size, cont_new, inst_arr) in - let typ_new = Sil.Tarray(elem_typ, typ_array_size) in + let array_new = Sil.Earray (array_len, cont_new, inst_arr) in + let typ_new = Sil.Tarray (elem_typ, typ_array_len) in [(atoms, array_new, typ_new)] end else begin @@ -317,8 +327,8 @@ and array_case_analysis_index pname tenv orig_prop pname tenv orig_prop footprint_part kind max_stamp typ_cont off inst in check_sound elem_typ; let cont_new = IList.sort Sil.exp_strexp_compare ((index, elem_se):: array_cont) in - let array_new = Sil.Earray(array_size, cont_new, inst_arr) in - let typ_new = Sil.Tarray(elem_typ, typ_array_size) in + let array_new = Sil.Earray (array_len, cont_new, inst_arr) in + let typ_new = Sil.Tarray (elem_typ, typ_array_len) in [(atoms, array_new, typ_new)] end in let rec handle_case acc isel_seen_rev = function @@ -330,10 +340,10 @@ and array_case_analysis_index pname tenv orig_prop let atoms_se_typ_list' = IList.fold_left (fun acc' (atoms', se', typ') -> check_sound typ'; - let atoms_new = Sil.Aeq(index, i) :: atoms' in + let atoms_new = Sil.Aeq (index, i) :: atoms' in let isel_new = list_rev_and_concat isel_seen_rev ((i, se'):: isel_unseen) in - let array_new = Sil.Earray(array_size, isel_new, inst_arr) in - let typ_new = Sil.Tarray(typ', typ_array_size) in + let array_new = Sil.Earray (array_len, isel_new, inst_arr) in + let typ_new = Sil.Tarray (typ', typ_array_len) in (atoms_new, array_new, typ_new):: acc' ) [] atoms_se_typ_list in let acc_new = atoms_se_typ_list' :: acc in @@ -927,7 +937,7 @@ let type_at_offset texp off = (IList.find (fun (f', _, _) -> Ident.fieldname_equal f f') instance_fields) in strip_offset off' typ' with Not_found -> None) - | (Sil.Off_index _):: off', Sil.Tarray (typ', _) -> + | (Sil.Off_index _) :: off', Sil.Tarray (typ', _) -> strip_offset off' typ' | _ -> None in match texp with diff --git a/infer/src/backend/serialization.ml b/infer/src/backend/serialization.ml index fa3c892d4..ccce64d7a 100644 --- a/infer/src/backend/serialization.ml +++ b/infer/src/backend/serialization.ml @@ -26,7 +26,7 @@ let tenv_key, summary_key, cfg_key, trace_key, cg_key, 799050016, 579094948, 972393003 (** version of the binary files, to be incremented for each change *) -let version = 24 +let version = 25 (** Retry the function while an exception filtered is thrown, diff --git a/infer/src/backend/symExec.ml b/infer/src/backend/symExec.ml index cdd24e782..6904c7ec0 100644 --- a/infer/src/backend/symExec.ml +++ b/infer/src/backend/symExec.ml @@ -170,11 +170,11 @@ let rec apply_offlist pp_error(); assert false - | (Sil.Off_index idx):: offlist', Sil.Earray (size, esel, inst1) -> + | (Sil.Off_index idx) :: offlist', Sil.Earray (len, esel, inst1) -> let nidx = Prop.exp_normalize_prop p idx in begin let typ' = Tenv.expand_type tenv typ in - let t', size' = match typ' with Sil.Tarray (t', size') -> (t', size') | _ -> assert false in + let t', len' = match typ' with Sil.Tarray (t', len') -> (t', len') | _ -> assert false in try let idx_ese', se' = IList.find (fun ese -> Prover.check_equal p nidx (fst ese)) esel in let res_e', res_se', res_t', res_pred_insts_op' = @@ -185,8 +185,8 @@ let rec apply_offlist if Sil.exp_equal idx_ese' (fst ese) then (idx_ese', res_se') else ese in - let res_se = Sil.Earray(size, IList.map replace_ese esel, inst1) in - let res_t = Sil.Tarray(res_t', size') in + let res_se = Sil.Earray (len, IList.map replace_ese esel, inst1) in + let res_t = Sil.Tarray (res_t', len') in (res_e', res_se, res_t, res_pred_insts_op') with Not_found -> (* return a nondeterministic value if the index is not found after rearrangement *) @@ -264,9 +264,9 @@ let rec execute_nullify_se = function | Sil.Estruct (fsel, _) -> let fsel' = IList.map (fun (fld, se) -> (fld, execute_nullify_se se)) fsel in Sil.Estruct (fsel', Sil.inst_nullify) - | Sil.Earray (size, esel, _) -> + | Sil.Earray (len, esel, _) -> let esel' = IList.map (fun (idx, se) -> (idx, execute_nullify_se se)) esel in - Sil.Earray (size, esel', Sil.inst_nullify) + Sil.Earray (len, esel', Sil.inst_nullify) (** Do pruning for conditional [if (e1 != e2) ] if [positive] is true and [(if (e1 == e2)] if [positive] is false *) diff --git a/infer/src/backend/tabulation.ml b/infer/src/backend/tabulation.ml index 52daf6af2..52c12a5ac 100644 --- a/infer/src/backend/tabulation.ml +++ b/infer/src/backend/tabulation.ml @@ -413,8 +413,8 @@ let rec sexp_set_inst inst = function Sil.Eexp (e, inst) | Sil.Estruct (fsel, _) -> Sil.Estruct ((IList.map (fun (f, se) -> (f, sexp_set_inst inst se)) fsel), inst) - | Sil.Earray (size, esel, _) -> - Sil.Earray (size, IList.map (fun (e, se) -> (e, sexp_set_inst inst se)) esel, inst) + | Sil.Earray (len, esel, _) -> + Sil.Earray (len, IList.map (fun (e, se) -> (e, sexp_set_inst inst se)) esel, inst) let rec fsel_star_fld fsel1 fsel2 = match fsel1, fsel2 with | [], fsel2 -> fsel2 @@ -447,11 +447,11 @@ and sexp_star_fld se1 se2 : Sil.strexp = match se1, se2 with | Sil.Estruct (fsel1, _), Sil.Estruct (fsel2, inst2) -> Sil.Estruct (fsel_star_fld fsel1 fsel2, inst2) - | Sil.Earray (size1, esel1, _), Sil.Earray (_, esel2, inst2) -> - Sil.Earray (size1, esel_star_fld esel1 esel2, inst2) - | Sil.Eexp (_, inst1), Sil.Earray (size2, esel2, _) -> + | Sil.Earray (len1, esel1, _), Sil.Earray (_, esel2, inst2) -> + Sil.Earray (len1, esel_star_fld esel1 esel2, inst2) + | Sil.Eexp (_, inst1), Sil.Earray (len2, esel2, _) -> let esel1 = [(Sil.exp_zero, se1)] in - Sil.Earray (size2, esel_star_fld esel1 esel2, inst1) + Sil.Earray (len2, esel_star_fld esel1 esel2, inst1) | _ -> L.d_str "cannot star "; Sil.d_sexp se1; L.d_str " and "; Sil.d_sexp se2; diff --git a/infer/src/clang/cTrans_utils.ml b/infer/src/clang/cTrans_utils.ml index d17be4aba..623f870c6 100644 --- a/infer/src/clang/cTrans_utils.ml +++ b/infer/src/clang/cTrans_utils.ml @@ -684,7 +684,7 @@ let var_or_zero_in_init_list tenv e typ ~return_zero:return_zero = let exp_types = zip lh_exprs lh_types in IList.map (fun (e, t) -> IList.flatten (var_or_zero_in_init_list' e t tns)) exp_types - | Sil.Tarray (arrtyp, Sil.Const (Sil.Cint n)) -> + | Sil.Tarray (arrtyp, Some n) -> let size = Sil.Int.to_int n in let indices = list_range 0 (size - 1) in let index_constants = diff --git a/infer/src/clang/cType_to_sil_type.ml b/infer/src/clang/cType_to_sil_type.ml index e988583f5..4ebdfaff5 100644 --- a/infer/src/clang/cType_to_sil_type.ml +++ b/infer/src/clang/cType_to_sil_type.ml @@ -61,10 +61,10 @@ let pointer_attribute_of_objc_attribute attr_info = | `OCL_Weak -> Sil.Pk_objc_weak | `OCL_Autoreleasing -> Sil.Pk_objc_autoreleasing -let rec build_array_type translate_decl tenv type_ptr n = +let rec build_array_type translate_decl tenv type_ptr n_opt = let array_type = type_ptr_to_sil_type translate_decl tenv type_ptr in - let exp = Sil.exp_int (Sil.Int.of_int64 (Int64.of_int n)) in - Sil.Tarray (array_type, exp) + let len = Option.map (fun n -> Sil.Int.of_int64 (Int64.of_int n)) n_opt in + Sil.Tarray (array_type, len) and sil_type_of_attr_type translate_decl tenv type_info attr_info = match type_info.Clang_ast_t.ti_desugared_type with @@ -96,9 +96,9 @@ and sil_type_of_c_type translate_decl tenv c_type = | IncompleteArrayType (_, type_ptr) | DependentSizedArrayType (_, type_ptr) | VariableArrayType (_, type_ptr) -> - build_array_type translate_decl tenv type_ptr (-1) + build_array_type translate_decl tenv type_ptr None | ConstantArrayType (_, type_ptr, n) -> - build_array_type translate_decl tenv type_ptr n + build_array_type translate_decl tenv type_ptr (Some n) | FunctionProtoType _ | FunctionNoProtoType _ -> Sil.Tfun false diff --git a/infer/src/eradicate/typeCheck.ml b/infer/src/eradicate/typeCheck.ml index 3ff4ee7db..a7c72e7e2 100644 --- a/infer/src/eradicate/typeCheck.ml +++ b/infer/src/eradicate/typeCheck.ml @@ -124,7 +124,6 @@ module ComplexExpressions = struct case_not_handled () | Sil.Dunop (op, de) -> Sil.str_unop op ^ dexp_to_string de - | Sil.Dsizeof _ -> case_not_handled () | Sil.Dunknown -> @@ -528,7 +527,7 @@ let typecheck_instr (typecheck_expr_simple typestate' e' typ TypeOrigin.ONone loc) typestate' | Sil.Call ([id], Sil.Const (Sil.Cfun pn), [(array_exp, t)], loc, _) - when Procname.equal pn ModelBuiltins.__get_array_size -> + when Procname.equal pn ModelBuiltins.__get_array_length -> let (_, ta, _) = typecheck_expr find_canonical_duplicate calls_this diff --git a/infer/src/harness/inhabit.ml b/infer/src/harness/inhabit.ml index 362711485..d2277edf2 100644 --- a/infer/src/harness/inhabit.ml +++ b/infer/src/harness/inhabit.ml @@ -84,10 +84,10 @@ let rec inhabit_typ typ cfg env = try (TypMap.find typ env.cache, env) with Not_found -> let inhabit_internal typ env = match typ with - | Sil.Tptr (Sil.Tarray (inner_typ, Sil.Const (Sil.Cint _)), Sil.Pk_pointer) -> - let arr_size = Sil.Const (Sil.Cint (Sil.Int.one)) in - let arr_typ = Sil.Tarray (inner_typ, arr_size) in - inhabit_alloc arr_typ (Some arr_size) typ ModelBuiltins.__new_array env + | Sil.Tptr (Sil.Tarray (inner_typ, Some _), Sil.Pk_pointer) -> + let len = Sil.Const (Sil.Cint (Sil.Int.one)) in + let arr_typ = Sil.Tarray (inner_typ, Some Sil.Int.one) in + inhabit_alloc arr_typ (Some len) typ ModelBuiltins.__new_array env | Sil.Tptr (typ, Sil.Pk_pointer) as ptr_to_typ -> (* TODO (t4575417): this case does not work correctly for enums, but they are currently * broken in Infer anyway (see t4592290) *) diff --git a/infer/src/java/jTrans.ml b/infer/src/java/jTrans.ml index dd54191be..67e91b6ff 100644 --- a/infer/src/java/jTrans.ml +++ b/infer/src/java/jTrans.ml @@ -400,8 +400,8 @@ let use_static_final_fields context = let builtin_new = Sil.Const (Sil.Cfun ModelBuiltins.__new) -let builtin_get_array_size = - Sil.Const (Sil.Cfun ModelBuiltins.__get_array_size) +let builtin_get_array_length = + Sil.Const (Sil.Cfun ModelBuiltins.__get_array_length) let create_sil_deref exp typ loc = let fresh_id = Ident.create_fresh Ident.knormal in @@ -447,7 +447,8 @@ let rec expression context pc expr = let deref = create_sil_deref sil_ex array_typ_no_ptr loc in let args = [(sil_ex, type_of_ex)] in let ret_id = Ident.create_fresh Ident.knormal in - let call_instr = Sil.Call([ret_id], builtin_get_array_size, args, loc, Sil.cf_default) in + let call_instr = + Sil.Call ([ret_id], builtin_get_array_length, args, loc, Sil.cf_default) in (instrs @ [deref; call_instr], Sil.Var ret_id, type_of_expr) | JBir.Conv conv -> let cast_ex = Sil.Cast (JTransType.cast_type conv, sil_ex) in @@ -478,7 +479,7 @@ let rec expression context pc expr = match binop with | JBir.ArrayLoad _ -> (* add an instruction that dereferences the array *) - let array_typ = Sil.Tarray(type_of_expr, Sil.Var (Ident.create_fresh Ident.kprimed)) in + let array_typ = Sil.Tarray (type_of_expr, None) in let deref_array_instr = create_sil_deref sil_ex1 array_typ loc in let id = Ident.create_fresh Ident.knormal in let letderef_instr = @@ -638,17 +639,17 @@ let method_invocation context loc pc var_opt cn ms sil_obj_opt expr_list invoke_ (callee_procname, instrs) -let get_array_size context pc expr_list content_type = +let get_array_length context pc expr_list content_type = let get_expr_instr expr other_instrs = - let (instrs, sil_size_expr, _) = expression context pc expr in + let (instrs, sil_len_expr, _) = expression context pc expr in match other_instrs with | (other_instrs, other_exprs) -> - (instrs@other_instrs, sil_size_expr:: other_exprs) in - let (instrs, sil_size_exprs) = (IList.fold_right get_expr_instr expr_list ([],[])) in - let get_array_type_len sil_size_expr (content_type, _) = - (Sil.Tarray (content_type, sil_size_expr), Some sil_size_expr) in + (instrs @ other_instrs, sil_len_expr :: other_exprs) in + let (instrs, sil_len_exprs) = (IList.fold_right get_expr_instr expr_list ([],[])) in + let get_array_type_len sil_len_expr (content_type, _) = + (Sil.Tarray (content_type, None), Some sil_len_expr) in let array_type, array_len = - IList.fold_right get_array_type_len sil_size_exprs (content_type, None) in + IList.fold_right get_array_type_len sil_len_exprs (content_type, None) in let array_size = Sil.Sizeof (array_type, array_len, Sil.Subtype.exact) in (instrs, array_size) @@ -925,7 +926,7 @@ let rec instruction context pc instr : translation = let content_type = JTransType.value_type program tenv vt in let array_type = JTransType.create_array_type content_type (IList.length expr_list) in let array_name = JContext.set_pvar context var array_type in - let (instrs, array_size) = get_array_size context pc expr_list content_type in + let (instrs, array_size) = get_array_length context pc expr_list content_type in let call_args = [(array_size, array_type)] in let ret_id = Ident.create_fresh Ident.knormal in let call_instr = Sil.Call([ret_id], builtin_new_array, call_args, loc, Sil.cf_default) in diff --git a/infer/src/java/jTransType.ml b/infer/src/java/jTransType.ml index ac206d62f..be6bed99f 100644 --- a/infer/src/java/jTransType.ml +++ b/infer/src/java/jTransType.ml @@ -69,8 +69,7 @@ let rec get_named_type vt = match ot with | JBasics.TArray vt -> let content_type = get_named_type vt in - let size = Sil.exp_get_undefined false in - Sil.Tptr (Sil.Tarray (content_type, size), Sil.Pk_pointer) (* unknown size *) + Sil.Tptr (Sil.Tarray (content_type, None), Sil.Pk_pointer) | JBasics.TClass cn -> Sil.Tptr (Sil.Tvar (typename_of_classname cn), Sil.Pk_pointer) end @@ -84,8 +83,7 @@ let extract_cn_type_np typ = let rec create_array_type typ dim = if dim > 0 then let content_typ = create_array_type typ (dim - 1) in - let size = Sil.exp_get_undefined false in - Sil.Tptr(Sil.Tarray (content_typ, size), Sil.Pk_pointer) + Sil.Tptr(Sil.Tarray (content_typ, None), Sil.Pk_pointer) else typ let extract_cn_no_obj typ = @@ -384,9 +382,7 @@ let is_closeable program tenv typ = let rec object_type program tenv ot = match ot with | JBasics.TClass cn -> get_class_type program tenv cn - | JBasics.TArray at -> - let size = Sil.exp_get_undefined false in - Sil.Tptr (Sil.Tarray (value_type program tenv at, size), Sil.Pk_pointer) + | JBasics.TArray at -> Sil.Tptr (Sil.Tarray (value_type program tenv at, None), Sil.Pk_pointer) (** translate a value type *) and value_type program tenv vt = match vt with @@ -397,9 +393,6 @@ and value_type program tenv vt = (** Translate object types into Sil.Sizeof expressions *) let sizeof_of_object_type program tenv ot subtypes = match object_type program tenv ot with - | Sil.Tptr (Sil.Tarray (vtyp, len), Sil.Pk_pointer) -> - let typ = (Sil.Tarray (vtyp, len)) in - Sil.Sizeof (typ, Some len, subtypes) | Sil.Tptr (typ, _) -> Sil.Sizeof (typ, None, subtypes) | _ -> diff --git a/infer/src/llvm/lTrans.ml b/infer/src/llvm/lTrans.ml index 336205238..97be414b6 100644 --- a/infer/src/llvm/lTrans.ml +++ b/infer/src/llvm/lTrans.ml @@ -36,7 +36,7 @@ let rec trans_typ : LAst.typ -> Sil.typ = function | Tfloat -> Sil.Tfloat Sil.FFloat | Tptr tp -> Sil.Tptr (trans_typ tp, Sil.Pk_pointer) | Tvector (i, tp) - | Tarray (i, tp) -> Sil.Tarray (trans_typ tp, Sil.Const (Sil.Cint (Sil.Int.of_int i))) + | Tarray (i, tp) -> Sil.Tarray (trans_typ tp, Some (Sil.Int.of_int i)) | Tfunc _ -> Sil.Tfun false | Tlabel -> raise (ImproperTypeError "Tried to generate Sil type from LLVM label type.") | Tmetadata -> raise (ImproperTypeError "Tried to generate Sil type from LLVM metadata type.") diff --git a/infer/tests/endtoend/java/tracing/ArrayIndexOutOfBoundsExceptionTest.java b/infer/tests/endtoend/java/tracing/ArrayIndexOutOfBoundsExceptionTest.java index db8092e3c..84a3f1ab2 100644 --- a/infer/tests/endtoend/java/tracing/ArrayIndexOutOfBoundsExceptionTest.java +++ b/infer/tests/endtoend/java/tracing/ArrayIndexOutOfBoundsExceptionTest.java @@ -42,9 +42,8 @@ public class ArrayIndexOutOfBoundsExceptionTest { public void matchErrors() throws IOException, InterruptedException, InferException { String[] methods = { -// TODO (#7651424): re-enable these tests once the translation of arrays is fixed -// "callOutOfBound", -// "missingCheckOnIndex", + "callOutOfBound", + "missingCheckOnIndex", "arrayIndexOutOfBoundsInCallee", }; assertThat(