From: Andrew Tridgell Date: Fri, 3 Dec 2004 06:24:38 +0000 (+0000) Subject: r4052: fixed a bunch of code to use the type safe _p allocation macros X-Git-Tag: samba-4.0.0alpha6~801^3~12419 X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=58c326809a816703dc516c3022c9c4dbb9d09445;p=samba.git r4052: fixed a bunch of code to use the type safe _p allocation macros (This used to be commit 80d15fa3402a9d1183467463f6b21c0b674bc442) --- diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 1254e26a73e..33f30203827 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -400,7 +400,7 @@ NTSTATUS make_auth_context_fixed(TALLOC_CTX *mem_ctx, } /* the list of currently registered AUTH backends */ -static struct { +static struct auth_backend { const struct auth_operations *ops; } *backends = NULL; static int num_backends; @@ -423,7 +423,8 @@ NTSTATUS auth_register(const void *_ops) return NT_STATUS_OBJECT_NAME_COLLISION; } - backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1)); + + backends = realloc_p(backends, struct auth_backend, num_backends+1); if (!backends) { smb_panic("out of memory in auth_register"); } diff --git a/source4/client/client.c b/source4/client/client.c index d9e995f1806..6af145c31e9 100644 --- a/source4/client/client.c +++ b/source4/client/client.c @@ -1449,7 +1449,7 @@ static int file_find(struct file_list **list, const char *directory, return -1; } } - entry = (struct file_list *) malloc(sizeof (struct file_list)); + entry = malloc_p(struct file_list); if (!entry) { d_printf("Out of memory in file_find\n"); closedir(dir); diff --git a/source4/client/tree.c b/source4/client/tree.c index 94fd93c2106..9776ce2ef74 100644 --- a/source4/client/tree.c +++ b/source4/client/tree.c @@ -129,7 +129,7 @@ char *get_path(GtkWidget *item) struct tree_data *make_tree_data(guint32 type, const char *name) { - struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data)); + struct tree_data *p = malloc_p(struct tree_data); if (p) { diff --git a/source4/lib/util.c b/source4/lib/util.c index 2351a98eae2..2d149e6e3dc 100644 --- a/source4/lib/util.c +++ b/source4/lib/util.c @@ -796,3 +796,20 @@ BOOL all_zero(const uint8_t *ptr, uint_t size) } return True; } + +/* + realloc an array, checking for integer overflow in the array size +*/ +void *realloc_array(void *ptr, size_t el_size, unsigned count) +{ +#define MAX_MALLOC_SIZE 0x7fffffff + if (count == 0 || + count >= MAX_MALLOC_SIZE/el_size) { + return NULL; + } + if (!ptr) { + return malloc(el_size * count); + } + return realloc(ptr, el_size * count); +} + diff --git a/source4/libads/ldap.c b/source4/libads/ldap.c index 9de73fcd0a0..d4b363cae64 100644 --- a/source4/libads/ldap.c +++ b/source4/libads/ldap.c @@ -1592,7 +1592,7 @@ char **ads_pull_strings(ADS_STRUCT *ads, *num_values = ldap_count_values(values); - ret = talloc(mem_ctx, sizeof(char *) * (*num_values+1)); + ret = talloc_array_p(mem_ctx, char *, *num_values+1); if (!ret) { ldap_value_free(values); return NULL; @@ -1839,7 +1839,7 @@ int ads_pull_sids(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, for (i=0; values[i]; i++) /* nop */ ; - (*sids) = talloc(mem_ctx, sizeof(DOM_SID) * i); + (*sids) = talloc_array_p(mem_ctx, DOM_SID, i); if (!(*sids)) { ldap_value_free_len(values); return 0; diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c index 7a72734c570..88c84d880ba 100644 --- a/source4/libcli/ldap/ldap_client.c +++ b/source4/libcli/ldap/ldap_client.c @@ -195,7 +195,7 @@ BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg, (msg->type == LDAP_TAG_UnbindRequest)) return True; - entry = malloc(sizeof(*entry)); + entry = malloc_p(struct ldap_queue_entry); if (entry == NULL) return False; @@ -243,7 +243,7 @@ static struct ldap_message *recv_from_queue(struct ldap_connection *conn, static void add_search_entry(struct ldap_connection *conn, struct ldap_message *msg) { - struct ldap_queue_entry *e = malloc(sizeof *e); + struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry); if (e == NULL) return; diff --git a/source4/libcli/namequery.c b/source4/libcli/namequery.c index 85270c10019..66154ef8f65 100644 --- a/source4/libcli/namequery.c +++ b/source4/libcli/namequery.c @@ -63,7 +63,7 @@ static struct node_status *parse_node_status(char *p, int *num_names) if (*num_names == 0) return NULL; - ret = (struct node_status *)malloc(sizeof(struct node_status)* (*num_names)); + ret = malloc_array_p(struct node_status, *num_names); if (!ret) return NULL; p++; @@ -619,7 +619,7 @@ static BOOL resolve_hosts(const char *name, if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { struct ipv4_addr return_ip; putip((char *)&return_ip,(char *)hp->h_addr); - *return_iplist = (struct ipv4_addr *)malloc(sizeof(struct ipv4_addr)); + *return_iplist = malloc_p(struct ipv4_addr); if(*return_iplist == NULL) { DEBUG(3,("resolve_hosts: malloc fail !\n")); return False; @@ -657,7 +657,7 @@ static BOOL internal_resolve_name(TALLOC_CTX *mem_ctx, const char *name, int nam DEBUG(10, ("internal_resolve_name: looking up %s#%x\n", name, name_type)); if (allzeros || allones || is_address) { - *return_iplist = (struct ipv4_addr *)malloc(sizeof(struct ipv4_addr)); + *return_iplist = malloc_p(struct ipv4_addr); if(*return_iplist == NULL) { DEBUG(3,("internal_resolve_name: malloc fail !\n")); return False; @@ -731,8 +731,7 @@ static BOOL internal_resolve_name(TALLOC_CTX *mem_ctx, const char *name, int nam controllers including the PDC in iplist[1..n]. Iterating over the iplist when the PDC is down will cause two sets of timeouts. */ - if (*return_count && (nodupes_iplist = (struct ipv4_addr *) - malloc(sizeof(struct ipv4_addr) * (*return_count)))) { + if (*return_count && (nodupes_iplist = malloc_array_p(struct ipv4_addr, *return_count))) { int nodupes_count = 0; /* Iterate over return_iplist looking for duplicates */ @@ -1156,7 +1155,7 @@ BOOL get_dc_list(TALLOC_CTX *mem_ctx, const char *domain, struct ipv4_addr **ip_ if ( (num_addresses == 0) && !done_auto_lookup ) return internal_resolve_name(mem_ctx, domain, 0x1C, ip_list, count); - return_iplist = (struct ipv4_addr *)malloc(num_addresses * sizeof(struct ipv4_addr)); + return_iplist = malloc_array_p(struct ipv4_addr, num_addresses); if (return_iplist == NULL) { DEBUG(3,("get_dc_list: malloc fail !\n")); diff --git a/source4/libcli/nmblib.c b/source4/libcli/nmblib.c index 06030f9aca1..70c6fab8da9 100644 --- a/source4/libcli/nmblib.c +++ b/source4/libcli/nmblib.c @@ -548,24 +548,21 @@ static struct packet_struct *copy_nmb_packet(struct packet_struct *packet) if (nmb->answers) { - if((copy_nmb->answers = (struct res_rec *) - malloc(nmb->header.ancount * sizeof(struct res_rec))) == NULL) + if((copy_nmb->answers = malloc_array_p(struct res_rec, nmb->header.ancount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->answers, (char *)nmb->answers, nmb->header.ancount * sizeof(struct res_rec)); } if (nmb->nsrecs) { - if((copy_nmb->nsrecs = (struct res_rec *) - malloc(nmb->header.nscount * sizeof(struct res_rec))) == NULL) + if((copy_nmb->nsrecs = malloc_array_p(struct res_rec, nmb->header.nscount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->nsrecs, (char *)nmb->nsrecs, nmb->header.nscount * sizeof(struct res_rec)); } if (nmb->additional) { - if((copy_nmb->additional = (struct res_rec *) - malloc(nmb->header.arcount * sizeof(struct res_rec))) == NULL) + if((copy_nmb->additional = malloc_array_p(struct res_rec, nmb->header.arcount)) == NULL) goto free_and_exit; memcpy((char *)copy_nmb->additional, (char *)nmb->additional, nmb->header.arcount * sizeof(struct res_rec)); @@ -591,7 +588,7 @@ static struct packet_struct *copy_dgram_packet(struct packet_struct *packet) { struct packet_struct *pkt_copy; - if(( pkt_copy = (struct packet_struct *)malloc(sizeof(*packet))) == NULL) + if(( pkt_copy = malloc_p(struct packet_struct)) == NULL) { DEBUG(0,("copy_dgram_packet: malloc fail.\n")); return NULL; @@ -663,7 +660,7 @@ struct packet_struct *parse_packet(char *buf,int length, struct packet_struct *p; BOOL ok=False; - p = (struct packet_struct *)malloc(sizeof(*p)); + p = malloc_p(struct packet_struct); if (!p) return(NULL); p->next = NULL; diff --git a/source4/librpc/idl/security.idl b/source4/librpc/idl/security.idl index 1ef1783073e..90ae3d3028c 100644 --- a/source4/librpc/idl/security.idl +++ b/source4/librpc/idl/security.idl @@ -184,7 +184,7 @@ interface security typedef [public] struct { uint16 revision; [value(ndr_size_security_acl(r))] uint16 size; - uint32 num_aces; + [range(0,1000)] uint32 num_aces; security_ace aces[num_aces]; } security_acl; diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index 71019030ac3..857e1712245 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -125,7 +125,7 @@ struct ndr_push *ndr_push_init_ctx(TALLOC_CTX *mem_ctx) { struct ndr_push *ndr; - ndr = talloc(mem_ctx, sizeof(*ndr)); + ndr = talloc_p(mem_ctx, struct ndr_push); if (!ndr) { return NULL; } diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c index 7e581992faf..844746e3223 100644 --- a/source4/librpc/rpc/dcerpc_auth.c +++ b/source4/librpc/rpc/dcerpc_auth.c @@ -70,7 +70,7 @@ NTSTATUS dcerpc_bind_auth3(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut } } - p->security_state.auth_info = talloc(p, sizeof(*p->security_state.auth_info)); + p->security_state.auth_info = talloc_p(p, struct dcerpc_auth); if (!p->security_state.auth_info) { status = NT_STATUS_NO_MEMORY; goto done; @@ -150,7 +150,7 @@ NTSTATUS dcerpc_bind_alter(struct dcerpc_pipe *p, uint8_t auth_type, uint8_t aut } } - p->security_state.auth_info = talloc(p, sizeof(*p->security_state.auth_info)); + p->security_state.auth_info = talloc_p(p, struct dcerpc_auth); if (!p->security_state.auth_info) { status = NT_STATUS_NO_MEMORY; goto done; diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 8947a5d2557..57beba8c687 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -222,7 +222,6 @@ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, struct odb_context *odb = lck->odb; TDB_DATA dbuf; struct odb_entry e; - char *tp; int i, count; struct odb_entry *elist; @@ -249,13 +248,13 @@ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle, } } - tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry)); - if (tp == NULL) { + elist = realloc_p(dbuf.dptr, struct odb_entry, count+1); + if (elist == NULL) { if (dbuf.dptr) free(dbuf.dptr); return NT_STATUS_NO_MEMORY; } - dbuf.dptr = tp; + dbuf.dptr = (char *)elist; dbuf.dsize = (count+1) * sizeof(struct odb_entry); memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)), @@ -279,7 +278,6 @@ NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private) struct odb_context *odb = lck->odb; TDB_DATA dbuf; struct odb_entry e; - char *tp; struct odb_entry *elist; int count; @@ -299,13 +297,13 @@ NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private) elist = (struct odb_entry *)dbuf.dptr; count = dbuf.dsize / sizeof(struct odb_entry); - tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry)); - if (tp == NULL) { + elist = realloc_p(dbuf.dptr, struct odb_entry, count+1); + if (elist == NULL) { if (dbuf.dptr) free(dbuf.dptr); return NT_STATUS_NO_MEMORY; } - dbuf.dptr = tp; + dbuf.dptr = (char *)elist; dbuf.dsize = (count+1) * sizeof(struct odb_entry); memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)), diff --git a/source4/ntvfs/ntvfs_base.c b/source4/ntvfs/ntvfs_base.c index 136ef14e4cc..ca6fbf0de8b 100644 --- a/source4/ntvfs/ntvfs_base.c +++ b/source4/ntvfs/ntvfs_base.c @@ -32,7 +32,7 @@ /* the list of currently registered NTVFS backends, note that there * can be more than one backend with the same name, as long as they * have different typesx */ -static struct { +static struct ntvfs_backend { const struct ntvfs_ops *ops; } *backends = NULL; static int num_backends; @@ -57,7 +57,7 @@ NTSTATUS ntvfs_register(const void *_ops) return NT_STATUS_OBJECT_NAME_COLLISION; } - backends = Realloc(backends, sizeof(backends[0]) * (num_backends+1)); + backends = realloc_p(backends, struct ntvfs_backend, num_backends+1); if (!backends) { smb_panic("out of memory in ntvfs_register"); } diff --git a/source4/param/params.c b/source4/param/params.c index 2a0cd13682f..a31d8d1b605 100644 --- a/source4/param/params.c +++ b/source4/param/params.c @@ -522,7 +522,7 @@ static myFILE *OpenConfFile( const char *FileName ) int lvl = in_client?1:0; myFILE *ret; - ret = (myFILE *)malloc(sizeof(*ret)); + ret = malloc_p(myFILE); if (!ret) return NULL; ret->buf = file_load(FileName, &ret->size); diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 3d34a7e1c0c..d11d5dddd87 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -1086,7 +1086,7 @@ static void dcesrv_exit(struct server_service *service, const char *reason) /* the list of currently registered DCERPC endpoint servers. */ -static struct { +static struct ep_server { struct dcesrv_endpoint_server *ep_server; } *ep_servers = NULL; static int num_ep_servers; @@ -1110,7 +1110,7 @@ NTSTATUS dcerpc_register_ep_server(const void *_ep_server) return NT_STATUS_OBJECT_NAME_COLLISION; } - ep_servers = Realloc(ep_servers, sizeof(ep_servers[0]) * (num_ep_servers+1)); + ep_servers = realloc_p(ep_servers, struct ep_server, num_ep_servers+1); if (!ep_servers) { smb_panic("out of memory in dcerpc_register"); } diff --git a/source4/rpc_server/spoolss/dcesrv_spoolss.c b/source4/rpc_server/spoolss/dcesrv_spoolss.c index 028471a715a..17c23dcba84 100644 --- a/source4/rpc_server/spoolss/dcesrv_spoolss.c +++ b/source4/rpc_server/spoolss/dcesrv_spoolss.c @@ -33,7 +33,7 @@ static WERROR spoolss_EnumPrinters1(TALLOC_CTX *mem_ctx, struct spoolss_PrinterInfo1 *info; int i; - info = talloc(mem_ctx, num_msgs * sizeof(struct spoolss_PrinterInfo1)); + info = talloc_array_p(mem_ctx, struct spoolss_PrinterInfo1, num_msgs); if (!info) return WERR_NOMEM; @@ -59,7 +59,7 @@ static WERROR spoolss_EnumPrinters2(TALLOC_CTX *mem_ctx, struct spoolss_PrinterInfo2 *info; int i; - info = talloc(mem_ctx, num_msgs * sizeof(struct spoolss_PrinterInfo1)); + info = talloc_array_p(mem_ctx, struct spoolss_PrinterInfo2, num_msgs); if (!info) return WERR_NOMEM; @@ -102,7 +102,7 @@ static WERROR spoolss_EnumPrinters5(TALLOC_CTX *mem_ctx, struct spoolss_PrinterInfo5 *info; int i; - info = talloc(mem_ctx, num_msgs * sizeof(struct spoolss_PrinterInfo1)); + info = talloc_array_p(mem_ctx, struct spoolss_PrinterInfo5, num_msgs); if (!info) return WERR_NOMEM; diff --git a/source4/rpc_server/srvsvc/dcesrv_srvsvc.c b/source4/rpc_server/srvsvc/dcesrv_srvsvc.c index d5ecd84f1a1..0679ac6e42b 100644 --- a/source4/rpc_server/srvsvc/dcesrv_srvsvc.c +++ b/source4/rpc_server/srvsvc/dcesrv_srvsvc.c @@ -904,7 +904,9 @@ static WERROR srvsvc_NetShareEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX if (r->out.ctr.ctr0->count == 0) break; - r->out.ctr.ctr0->array = talloc(mem_ctx, r->out.ctr.ctr0->count*sizeof(struct srvsvc_NetShareInfo0)); + r->out.ctr.ctr0->array = talloc_array_p(mem_ctx, + struct srvsvc_NetShareInfo0, + r->out.ctr.ctr0->count); WERR_TALLOC_CHECK(r->out.ctr.ctr0->array); for (i=0;iout.ctr.ctr0->count;i++) { @@ -926,7 +928,9 @@ static WERROR srvsvc_NetShareEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX if (r->out.ctr.ctr1->count == 0) break; - r->out.ctr.ctr1->array = talloc(mem_ctx, r->out.ctr.ctr1->count*sizeof(struct srvsvc_NetShareInfo1)); + r->out.ctr.ctr1->array = talloc_array_p(mem_ctx, + struct srvsvc_NetShareInfo1, + r->out.ctr.ctr1->count); WERR_TALLOC_CHECK(r->out.ctr.ctr1->array); for (i=0;iout.ctr.ctr1->count;i++) { @@ -949,7 +953,9 @@ static WERROR srvsvc_NetShareEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX if (r->out.ctr.ctr2->count == 0) break; - r->out.ctr.ctr2->array = talloc(mem_ctx, r->out.ctr.ctr2->count*sizeof(struct srvsvc_NetShareInfo2)); + r->out.ctr.ctr2->array = talloc_array_p(mem_ctx, + struct srvsvc_NetShareInfo2, + r->out.ctr.ctr2->count); WERR_TALLOC_CHECK(r->out.ctr.ctr2->array); for (i=0;iout.ctr.ctr2->count;i++) { @@ -977,7 +983,9 @@ static WERROR srvsvc_NetShareEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX if (r->out.ctr.ctr501->count == 0) break; - r->out.ctr.ctr501->array = talloc(mem_ctx, r->out.ctr.ctr501->count*sizeof(struct srvsvc_NetShareInfo501)); + r->out.ctr.ctr501->array = talloc_array_p(mem_ctx, + struct srvsvc_NetShareInfo501, + r->out.ctr.ctr501->count); WERR_TALLOC_CHECK(r->out.ctr.ctr501->array); for (i=0;iout.ctr.ctr501->count;i++) { @@ -1001,7 +1009,9 @@ static WERROR srvsvc_NetShareEnum(struct dcesrv_call_state *dce_call, TALLOC_CTX if (r->out.ctr.ctr502->count == 0) break; - r->out.ctr.ctr502->array = talloc(mem_ctx, r->out.ctr.ctr502->count*sizeof(struct srvsvc_NetShareInfo502)); + r->out.ctr.ctr502->array = talloc_array_p(mem_ctx, + struct srvsvc_NetShareInfo502, + r->out.ctr.ctr502->count); WERR_TALLOC_CHECK(r->out.ctr.ctr502->array); for (i=0;iout.ctr.ctr502->count;i++) { diff --git a/source4/torture/locktest.c b/source4/torture/locktest.c index d25625df1e0..9c7c3632596 100644 --- a/source4/torture/locktest.c +++ b/source4/torture/locktest.c @@ -317,7 +317,7 @@ static void test_locks(char *share[NSERVERS]) ZERO_STRUCT(fnum); ZERO_STRUCT(cli); - recorded = (struct record *)malloc(sizeof(*recorded) * numops); + recorded = malloc_array_p(struct record, numops); for (n=0; ncount * sizeof(names[0])); + names = talloc_array_p(mem_ctx, struct lsa_String, tnames->count); for (i=0;icount;i++) { init_lsa_String(&names[i], tnames->names[i].name.string); } @@ -160,7 +160,7 @@ static BOOL test_LookupNames2(struct dcerpc_pipe *p, sids.count = 0; sids.sids = NULL; - names = talloc(mem_ctx, tnames->count * sizeof(names[0])); + names = talloc_array_p(mem_ctx, struct lsa_String, tnames->count); for (i=0;icount;i++) { init_lsa_String(&names[i], tnames->names[i].name.string); } diff --git a/source4/torture/rpc/samr.c b/source4/torture/rpc/samr.c index 0fa1bccace8..c7456e2fdad 100644 --- a/source4/torture/rpc/samr.c +++ b/source4/torture/rpc/samr.c @@ -2136,7 +2136,7 @@ static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("Testing LookupNames\n"); n.in.domain_handle = handle; n.in.num_names = r.out.sam->count; - n.in.names = talloc(mem_ctx, r.out.sam->count * sizeof(struct samr_String)); + n.in.names = talloc_array_p(mem_ctx, struct samr_String, r.out.sam->count); for (i=0;icount;i++) { n.in.names[i] = r.out.sam->entries[i].name; } @@ -2150,7 +2150,7 @@ static BOOL test_EnumDomainUsers(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, printf("Testing LookupRids\n"); lr.in.domain_handle = handle; lr.in.num_rids = r.out.sam->count; - lr.in.rids = talloc(mem_ctx, r.out.sam->count * sizeof(uint32_t)); + lr.in.rids = talloc_array_p(mem_ctx, uint32_t, r.out.sam->count); for (i=0;icount;i++) { lr.in.rids[i] = r.out.sam->entries[i].idx; } diff --git a/source4/torture/torture.c b/source4/torture/torture.c index f5b45021c5f..af5c9a2f8ee 100644 --- a/source4/torture/torture.c +++ b/source4/torture/torture.c @@ -1422,7 +1422,7 @@ static BOOL run_pipe_number(void) printf("Opening %d connections\n", torture_numops); - cli = malloc(sizeof(struct smbcli_state *) * torture_numops); + cli = malloc_array_p(struct smbcli_state *, torture_numops); for (i=0;i