* Do not use strcpy/strcat/sprintf

- There are still some 3rd party files that require update
  - Makes OpenBSD linking less verbose
This commit is contained in:
pancake 2011-07-06 03:01:21 +02:00
parent 45a6b0d2ce
commit 510c08f4e4
15 changed files with 159 additions and 110 deletions

View File

@ -87,7 +87,7 @@ int main(int argc, char **argv) {
int fullfile = 0;
ut32 bsize = 0;
ut64 seek = 0;
char file[1024];
char file[4096];
char *cmdfile = NULL;
int is_gdb = R_FALSE;
@ -151,12 +151,12 @@ int main(int argc, char **argv) {
}
if (debug) {
int filelen = 0;
r_config_set (r.config, "io.va", "false"); // implicit?
r_config_set (r.config, "cfg.debug", "true");
is_gdb = (!memcmp (argv[optind], "gdb://", 6));
if (!is_gdb)
strcpy (file, "dbg://");
else *file = 0;
if (is_gdb) *file = 0;
else memcpy (file, "dbg://", 7);
if (optind < argc) {
char *ptr = r_file_path (argv[optind]);
if (ptr) {
@ -166,10 +166,23 @@ int main(int argc, char **argv) {
}
}
while (optind < argc) {
strcat (file, argv[optind]);
strcat (file, " ");
if (++optind != argc)
strcat (file, " ");
int largv = strlen (argv[optind]);
if (filelen+largv+1>=sizeof (file)) {
eprintf ("Too long arguments\n");
return 1;
}
memcpy (file+filelen, argv[optind], largv);
filelen += largv;
if (filelen+6>=sizeof (file)) {
eprintf ("Too long arguments\n");
return 1;
}
memcpy (file+filelen, " ", 2);
filelen += 2;
if (++optind != argc) {
memcpy (file+filelen, " ", 2);
filelen += 2;
}
}
fh = r_core_file_open (&r, file, perms, 0LL);

View File

@ -118,7 +118,7 @@ static void rcc_pushstr(char *str, int filter) {
default: dotrim = 0; break;
}
if (dotrim)
strcpy (str+i+1, str+i+2); // Add STRBCPY macro
memmove (str+i+1, str+i+2, strlen (str+i+2));
}
}
@ -184,7 +184,8 @@ char *mk_var(char *out, const char *_str, int delta) {
}
} else
if (!memcmp (str+1, "reg", 3)) {
sprintf (out, "%%%s", emit->regs (atoi (str+4)));
// XXX: can overflow if out is small
snprintf (out, 32, "%%%s", emit->regs (atoi (str+4)));
} else {
ret = str; /* TODO: show error, invalid var name? */
eprintf ("FUCKED UP\n");
@ -197,7 +198,7 @@ char *mk_var(char *out, const char *_str, int delta) {
str++;
len = strlen (str)-1;
str[len]='\0';
sprintf (foo, ".fix%d", nargs*16); /* XXX FIX DELTA !!!1 */
snprintf (foo, sizeof (foo)-1, ".fix%d", nargs*16); /* XXX FIX DELTA !!!1 */
dstvar = strdup (foo);
rcc_pushstr (str, mustfilter);
ret = mk_var (out, foo, 0);

View File

@ -16,7 +16,7 @@ OBJ=bin.o bin_meta.o bin_write.o demangle.o ${STATIC_OBJS}
OBJ+=mangling/cxx/cp-demangle.o
pre:
if [ ! -e libr_bin.${EXT_SO} ]; then rm -f ${STATIC_OBJS} ; fi
@if [ ! -e libr_bin.${EXT_SO} ]; then rm -f ${STATIC_OBJS} ; fi
plugins:
cd p && ${MAKE} all

View File

@ -99,10 +99,10 @@ R_API char *r_bin_demangle (RBin *bin, const char *str) {
#ifdef TEST
main() {
char *out, str[128];
strcpy (str, "_Z1hic");
strcpy (str, "main(Ljava/lang/String;I)V");
strcpy (str, "main([Ljava/lang/String;)V");
strcpy (str, "foo([III)Ljava/lang/Polla;");
strncpy (str, "_Z1hic", sizeof (str));
strncpy (str, "main(Ljava/lang/String;I)V", sizeof (str));
strncpy (str, "main([Ljava/lang/String;)V", sizeof (str));
strncpy (str, "foo([III)Ljava/lang/Polla;", sizeof (str));
//out = cplus_demangle_v3 (str, flags);
out = r_bin_demangle_java (str); //, flags);
printf ("INPUT (%s)\n", str);

View File

@ -159,55 +159,55 @@ static int javasm_init(struct r_bin_java_obj_t *bin) {
/* Initialize cp_null_item */
cp_null_item.tag = -1;
strcpy(cp_null_item.name, "(null)");
cp_null_item.value = strdup("(null)");
strncpy (cp_null_item.name, "(null)", sizeof (cp_null_item.name)-1);
cp_null_item.value = strdup ("(null)");
/* start parsing */
r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)&bin->cf, 10); //sizeof(struct r_bin_java_classfile_t), 1, bin->fd);
if (memcmp(bin->cf.cafebabe, "\xCA\xFE\xBA\xBE", 4)) {
r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)&bin->cf, 10); //sizeof(struct r_bin_java_classfile_t), 1, bin->fd);
if (memcmp (bin->cf.cafebabe, "\xCA\xFE\xBA\xBE", 4)) {
fprintf(stderr, "Invalid header\n");
return R_FALSE;
}
bin->cf.cp_count = R_BIN_JAVA_SWAPUSHORT(bin->cf.cp_count);
bin->cf.cp_count = R_BIN_JAVA_SWAPUSHORT (bin->cf.cp_count);
if (bin->cf.major[0]==bin->cf.major[1] && bin->cf.major[0]==0) {
fprintf(stderr, "This is a MachO\n");
return R_FALSE;
}
bin->cf.cp_count--;
IFDBG printf("ConstantPoolCount %d\n", bin->cf.cp_count);
IFDBG printf ("ConstantPoolCount %d\n", bin->cf.cp_count);
bin->cp_items = malloc (sizeof (struct r_bin_java_cp_item_t)*(bin->cf.cp_count+1));
for(i=0;i<bin->cf.cp_count;i++) {
struct constant_t *c;
r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, 1);
r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 1);
c = NULL;
for(j=0;constants[j].name;j++) {
for (j=0;constants[j].name;j++) {
if (constants[j].tag == buf[0]) {
c = &constants[j];
break;
}
}
if (c == NULL) {
fprintf(stderr, "Invalid tag '%d' at offset 0x%08"PFMT64x"\n",
buf[0], (ut64)bin->b->cur);
fprintf (stderr, "Invalid tag '%d' at offset 0x%08"PFMT64x"\n",
*buf, (ut64)bin->b->cur);
return R_FALSE;
}
IFDBG printf(" %3d %s: ", i+1, c->name);
IFDBG printf (" %3d %s: ", i+1, c->name);
/* store constant pool item */
strcpy(bin->cp_items[i].name, c->name);
strncpy (bin->cp_items[i].name, c->name, sizeof (bin->cp_items[i].name)-1);
bin->cp_items[i].ord = i+1;
bin->cp_items[i].tag = c->tag;
bin->cp_items[i].value = NULL; // no string by default
bin->cp_items[i].off = bin->b->cur-1;
/* read bytes */
switch(c->tag) {
switch (c->tag) {
case 1: // Utf8 string
r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, 2);
r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 2);
sz = R_BIN_JAVA_USHORT (buf, 0);
bin->cp_items[i].length = sz;
bin->cp_items[i].off += 3;
@ -311,7 +311,7 @@ static int javasm_init(struct r_bin_java_obj_t *bin) {
bin->methods[i].name = strdup((get_cp(bin, R_BIN_JAVA_USHORT(buf, 2)-1))->value);
#else
bin->methods[i].name = malloc (1024);
sprintf (bin->methods[i].name, "%s%s",
snprintf (bin->methods[i].name, 1023, "%s%s",
(get_cp(bin, R_BIN_JAVA_USHORT(buf, 2)-1))->value,
(get_cp(bin, R_BIN_JAVA_USHORT(buf, 2)))->value);
#endif

View File

@ -3347,7 +3347,7 @@ static inline void
d_append_num (struct d_print_info *dpi, long l)
{
char buf[25];
sprintf (buf,"%ld", l);
snprintf (buf,sizeof (buf), "%ld", l);
d_append_string (dpi, buf);
}
@ -4946,7 +4946,7 @@ __cxa_demangle (const char *mangled_name, char *output_buffer,
{
if (strlen (demangled) < *length)
{
strcpy (output_buffer, demangled);
strncpy (output_buffer, demangled, *length);
free (demangled);
demangled = output_buffer;
}

View File

@ -90,15 +90,21 @@ R_API int r_cmd_call(struct r_cmd_t *cmd, const char *input) {
R_API int r_cmd_call_long(struct r_cmd_t *cmd, const char *input) {
char *inp;
struct list_head *pos;
int inplen = strlen(input)+1;
int ret, inplen = strlen (input)+1;
list_for_each_prev (pos, &cmd->lcmds) {
RCmdLongItem *c = list_entry (pos, struct r_cmd_long_item_t, list);
if (inplen>=c->cmd_len && !r_str_cmp (input, c->cmd, c->cmd_len)) {
inp = alloca(inplen);
strcpy (inp, c->cmd_short);
strcat (inp, input+c->cmd_len);
return r_cmd_call (cmd, inp);
int lcmd = strlen (c->cmd_short);
int linp = strlen (input+c->cmd_len);
inp = malloc (lcmd+linp+2); // TODO: use static buffer with R_CMD_MAXLEN
if (inp == NULL)
return -1;
memcpy (inp, c->cmd_short, lcmd);
memcpy (inp+lcmd, input+c->cmd_len, linp+1);
ret = r_cmd_call (cmd, inp);
free (inp);
return ret;
}
}
return -1;

View File

@ -28,7 +28,7 @@ R_API void r_cmd_macro_init(RCmdMacro *mac) {
R_API int r_cmd_macro_add(RCmdMacro *mac, const char *oname) {
struct list_head *pos;
struct r_cmd_macro_item_t *macro;
char buf[4096];
char buf[R_CMD_MAXLEN];
char *bufp;
char *pbody;
char *ptr;
@ -36,7 +36,7 @@ R_API int r_cmd_macro_add(RCmdMacro *mac, const char *oname) {
int macro_update;
char *name, *args = NULL;
if (oname[0]=='\0') {
if (!*oname) {
r_cmd_macro_list (mac);
return 0;
}
@ -80,12 +80,13 @@ R_API int r_cmd_macro_add(RCmdMacro *mac, const char *oname) {
if (ptr)
*ptr = ' ';
if (macro == NULL) {
macro = (struct r_cmd_macro_item_t *)malloc (sizeof(struct r_cmd_macro_item_t));
macro = (struct r_cmd_macro_item_t *)malloc (sizeof (struct r_cmd_macro_item_t));
macro->name = strdup (name);
}
if (pbody) macro->code = (char *)malloc (strlen (pbody)+2);
else macro->code = (char *)malloc (4096);
macro->code[0]='\0';
macro->codelen = (pbody)? strlen (pbody)+2 : 4096;
macro->code = (char *)malloc (macro->codelen);
*macro->code = '\0';
macro->nargs = 0;
if (args == NULL)
args = "";
@ -104,10 +105,11 @@ R_API int r_cmd_macro_add(RCmdMacro *mac, const char *oname) {
if (pbody[lidx]==')' && pbody[lidx-1]=='\n')
pbody[lidx]='\0';
}
strcpy (macro->code, pbody);
strncpy (macro->code, pbody, macro->codelen);
//strcat (macro->code, ",");
} else {
for (;;) { // XXX input from mac->fd
int lbufp, codelen = 0;
for (;codelen<R_CMD_MAXLEN;) { // XXX input from mac->fd
#if 0
if (stdin == r_cons_stdin_fd) {
mac->printf(".. ");
@ -115,18 +117,21 @@ R_API int r_cmd_macro_add(RCmdMacro *mac, const char *oname) {
}
fgets(buf, 1023, r_cons_stdin_fd);
#endif
fgets (buf, sizeof (buf), stdin);
if (buf[0]==')')
fgets (buf, sizeof (buf)-1, stdin);
if (*buf==')')
break;
for (bufp=buf;*bufp==' '||*bufp=='\t';bufp=bufp+1);
lidx = strlen(buf)-2;
for (bufp=buf;*bufp==' '||*bufp=='\t';bufp++);
lidx = strlen (buf)-2;
lbufp = strlen (bufp);
if (buf[lidx]==')' && buf[lidx-1]!='(') {
buf[lidx]='\0';
strcat (macro->code, bufp);
memcpy (macro->code+codelen, bufp, lbufp+1);
break;
}
if (*buf != '\n')
strcat (macro->code, bufp);
if (*buf != '\n') {
memcpy (macro->code+codelen, bufp, lbufp+1);
codelen += lbufp;
}
}
}
if (macro_update == 0)
@ -185,51 +190,65 @@ R_API void r_cmd_macro_list(RCmdMacro *mac) {
#endif
R_API int r_cmd_macro_cmd_args(RCmdMacro *mac, const char *ptr, const char *args, int nargs) {
int i,j;
char *cmd = alloca(strlen(ptr)+1024);
char *arg = args?strdup(args):strdup("");
cmd[0]='\0';
int i, j;
char *pcmd, cmd[R_CMD_MAXLEN];
char *arg = args? strdup (args): strdup ("");
*cmd = '\0';
for (i=j=0; ptr[j]; i++,j++) {
for (i=j=0; ptr[j] && j<R_CMD_MAXLEN; i++,j++) {
if (ptr[j]=='$') {
if (ptr[j+1]>='0' && ptr[j+1]<='9') {
int wordlen;
char *word = r_str_word_get0 (arg, ptr[j+1]-'0');
strcat (cmd, word);
j++;
i = strlen (cmd)-1;
if (word) {
wordlen = strlen (word);
if ((i+wordlen+1) >= sizeof (cmd)) {
free (arg);
return -1;
}
memcpy (cmd+i, word, wordlen+1);
i += wordlen-1;
j++;
}
} else
if (ptr[j+1]=='@') {
char off[32];
sprintf(off, "%d", mac->counter);
strcat(cmd, off);
int offlen;
offlen = snprintf (off, sizeof (off), "%d", mac->counter);
if ((i+offlen+1) >= sizeof (cmd)) {
free (arg);
return -1;
}
memcpy (cmd+i, off, offlen+1);
i += offlen-1;
j++;
i = strlen(cmd)-1;
} else {
cmd[i]=ptr[j];
cmd[i+1]='\0';
}
} else {
cmd[i]=ptr[j];
cmd[i+1]='\0';
cmd[i] = ptr[j];
cmd[i+1] = '\0';
}
}
while(*cmd==' '||*cmd=='\t')
cmd = cmd + 1;
pcmd = cmd;
while (*pcmd==' '||*cmd=='\t')
pcmd++;
free (arg);
return (*cmd==')')?0:mac->cmd (mac->user, cmd);
return (*pcmd==')')? 0: mac->cmd (mac->user, pcmd);
}
R_API char *r_cmd_macro_label_process(RCmdMacro *mac, RCmdMacroLabel *labels, int *labels_n, char *ptr) {
int i;
for (;ptr[0]==' ';ptr=ptr+1);
if (ptr[strlen(ptr)-1]==':') {
for (; *ptr==' '; ptr++);
if (ptr[strlen (ptr)-1]==':') {
/* label detected */
if (ptr[0]=='.') {
// eprintf("---> GOTO '%s'\n", ptr+1);
/* goto */
for(i=0;i<*labels_n;i++) {
for (i=0;i<*labels_n;i++) {
// eprintf("---| chk '%s'\n", labels[i].name);
if (!strcmp(ptr+1, labels[i].name))
if (!strcmp (ptr+1, labels[i].name))
return labels[i].ptr;
}
return NULL;

View File

@ -663,7 +663,7 @@ static const char *r_debug_native_reg_profile(RDebug *dbg) {
#if __APPLE__
// XXX
static RDebugPid *darwin_get_pid(int pid) {
int foo, nargs, mib[3];
int psnamelen, foo, nargs, mib[3];
size_t size, argmax = 2048;
char *curr_arg, *start_args, *iter_args, *end_args;
char *procargs = NULL;
@ -735,16 +735,18 @@ static RDebugPid *darwin_get_pid(int pid) {
curr_arg = iter_args;
start_args = iter_args; //reset start position to beginning of cmdline
foo = 1;
psname[0] = 0;
*psname = 0;
while (iter_args < end_args && nargs > 0) {
if (*iter_args++ == '\0') {
int alen = strlen (curr_arg);
if (foo) {
strcpy (psname, curr_arg);
memcpy (psname, curr_arg, alen+1);
foo = 0;
} else {
strcat (psname, " ");
strcat (psname, curr_arg);
psname[psnamelen] = ' ';
memcpy (psname+psnamelen+1, curr_arg, alen+1);
}
psnamelen += alen;
//printf("arg[%i]: %s\n", iter_args, curr_arg);
/* Fetch next argument */
curr_arg = iter_args;
@ -931,9 +933,9 @@ static RList *r_debug_native_threads(int pid) {
int tgid = atoi (ptr+5);
if (tgid != pid)
continue;
read (fd, cmdline, sizeof(cmdline)-1);
sprintf (cmdline, "thread_%d", thid++);
cmdline[sizeof(cmdline)-1] = '\0';
read (fd, cmdline, sizeof (cmdline)-1);
snprintf (cmdline, sizeof (cmdline), "thread_%d", thid++);
cmdline[sizeof (cmdline)-1] = '\0';
r_list_append (list, r_debug_pid_new (cmdline, i, 's', 0));
}
}
@ -1152,8 +1154,6 @@ static const char * unparse_inheritance (vm_inherit_t i) {
// TODO: this loop MUST be cleaned up
static RList *darwin_dbg_maps (RDebug *dbg) {
RDebugMap *mr;
RList *list = r_list_new ();
char buf[128];
int i, print;
kern_return_t kret;
@ -1164,9 +1164,10 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
mach_msg_type_number_t count;
int nsubregions = 0;
int num_printed = 0;
// XXX: wrong for 64bits
size_t address = 0;
task_t task = pid_to_task (dbg->pid);
RList *list = r_list_new ();
// XXX: wrong for 64bits
/*
count = VM_REGION_BASIC_INFO_COUNT_64;
kret = mach_vm_region (pid_to_task (dbg->pid), &address, &size, VM_REGION_BASIC_INFO_64,
@ -1217,7 +1218,7 @@ static RList *darwin_dbg_maps (RDebug *dbg) {
#define xwr2rwx(x) ((x&1)<<2) && (x&2) && ((x&4)>>2)
if (print) {
sprintf (buf, "%s %02x %s/%s/%s",
snprintf (buf, sizeof (buf), "%s %02x %s/%s/%s",
r_str_rwx_i (xwr2rwx (prev_info.max_protection)), i,
unparse_inheritance (prev_info.inheritance),
prev_info.shared ? "shar" : "priv",
@ -1286,7 +1287,7 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
#if __sun
char path[1024];
/* TODO: On solaris parse /proc/%d/map */
sprintf (path, "pmap %d > /dev/stderr", ps.tid);
snprintf (path, sizeof (path)-1, "pmap %d > /dev/stderr", ps.tid);
system (path);
#else
RDebugMap *map;
@ -1301,9 +1302,9 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
}
#if __FreeBSD__
sprintf (path, "/proc/%d/map", dbg->pid);
snprintf (path, sizeof (path), "/proc/%d/map", dbg->pid);
#else
sprintf (path, "/proc/%d/maps", dbg->pid);
snprintf (path, sizeof (path), "/proc/%d/maps", dbg->pid);
#endif
fd = fopen (path, "r");
if (!fd) {
@ -1326,7 +1327,7 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
&region[2], &region2[2], &ign, &ign,
unkstr, perms, &ign, &ign);
pos_c = strchr (line, '/');
if (pos_c) strcpy (path, pos_c);
if (pos_c) strncpy (path, pos_c, sizeof (path)-1);
else path[0]='\0';
#else
sscanf (line, "%s %s %s %s %s %s",
@ -1338,13 +1339,13 @@ static RList *r_debug_native_map_get(RDebug *dbg) {
pos_c[-1] = (char)'0';
pos_c[ 0] = (char)'x';
strcpy (region2, pos_c-1);
strncpy (region2, pos_c-1, sizeof (region2));
#endif // __FreeBSD__
region[0] = region2[0] = '0';
region[1] = region2[1] = 'x';
if (!*path)
sprintf (path, "unk%d", unk++);
snprintf (path, sizeof (path), "unk%d", unk++);
perm = 0;
for(i = 0; perms[i] && i < 4; i++)

View File

@ -7,6 +7,7 @@
#define MACRO_LIMIT 1024
#define MACRO_LABELS 20
#define R_CMD_MAXLEN 4096
#define r_cmd_callback(x) int (*x)(void *data, const char *input)
#define r_cmd_nullcallback(x) int (*x)(void *data);
@ -20,6 +21,7 @@ typedef struct r_cmd_macro_item_t {
char *name;
char *args;
char *code;
int codelen;
int nargs;
struct list_head list;
} RCmdMacroItem;

View File

@ -105,7 +105,7 @@ typedef void (*PrintfCallback)(const char *str, ...);
/* TODO: Move outside */
#define _perror(str,file,line) \
{ char buf[128];sprintf(buf, "%s:%d %s", file,line,str);perror(buf); }
{ char buf[128];snprintf(buf,sizeof(buf),"%s:%d %s",file,line,str);perror(buf); }
#define perror(x) _perror(x,__FILE__,__LINE__)
#define eprintf(x,y...) fprintf(stderr,x,##y)

View File

@ -15,15 +15,23 @@
#include <openssl/bn.h>
#endif
#define R_REFCTR_CLASS(x) int refctr;void (*ref_free)(x)=x;
#define R_REFCTR_REF(x) x->refctr++;
// TODO: use lowercase here?
#define R_REFCTR_CLASS int refctr;void (*ref_free)(x)
#define R_REFCTR_INIT(x,y) x->refctr=0;x->ref_free=y
#define R_REFCTR_REF(x) x->refctr++
#define R_REFCTR_UNREF(x) if (--x->refctr<=0) x->ref_free(x)
#if 0
typedef struct {
R_REFCTR_CLASS(r_foo_free);
R_REFCTR_CLASS;
} Foo;
Foo *r_foo_new () {
Foo *f = R_NEW(Foo)
R_REFCTR_INIT (f, r_foo_free);
...
return f;
}
Foo *foo = r_foo_new (Foo)
R_REFCTR_REF (foo)
R_REFCTR_UNREF (foo)

View File

@ -63,14 +63,13 @@ R_API int r_io_redirect(struct r_io_t *io, const char *file) {
R_API RIODesc *r_io_open_as(struct r_io_t *io, const char *urihandler, const char *file, int flags, int mode) {
RIODesc *ret;
char *uri;
int urilen = strlen (urihandler);
uri = malloc (strlen (urihandler)+strlen (file)+5);
int urilen, hlen = strlen (urihandler);
urilen = hlen + strlen (file)+5;
uri = malloc (urilen);
if (uri == NULL)
return NULL;
if (urilen>0)
sprintf (uri, "%s://", urihandler);
else *uri = '\0';
strcpy (uri+urilen, file);
if (hlen>0) snprintf (uri, urilen, "%s://%s", urihandler, file);
else strncpy (uri, file, urilen);
ret = r_io_open (io, uri, flags, mode);
free (uri);
return ret;

View File

@ -34,24 +34,24 @@ R_API int r_hex_pair2bin(const char *arg) {
}
R_API int r_hex_bin2str(const ut8 *in, int len, char *out) {
int i;
int i, idx;
char tmp[5];
out[0]='\0';
for (i=0; i<len; i++) {
for (idx=i=0; i<len; i++,idx+=2) {
snprintf (tmp, sizeof (tmp), "%02x", in[i]);
strcat (out, tmp);
memcpy (out+idx, tmp, 2);
}
out[idx] = 0;
return len;
}
R_API char *r_hex_bin2strdup(const ut8 *in, int len) {
int i;
int i, idx;
char tmp[5], *out = malloc ((len+1)*2);
out[0]='\0';
for (i=0; i<len; i++) {
for (i=idx=0; i<len; i++, idx+=2) {
snprintf (tmp, sizeof (tmp), "%02x", in[i]);
strcat (out, tmp);
memcpy (out+idx, tmp, 2);
}
out[idx] = 0;
return out;
}