1
void *buffer[10];
int size = backtrace(buffer, 10);
char cmd[1024];
sprintf(cmd, "addr2line -f -p -e a.out %p %p %p %p %p %p %p %p %p %p",
    buffer[0],
    buffer[1],
    buffer[2],
    buffer[3],
    buffer[4],
    buffer[5],
    buffer[6],
    buffer[7],
    buffer[8],
    buffer[9],
);

I have this code, works most of the time, but sometimes size is less than 10, how to easily print size pointers from an array buffer?

3
  • 3
    Use a loop. (sprintf() returns the number of written characters or -1) Commented Feb 24, 2018 at 15:09
  • Why are you using void *? Commented Feb 24, 2018 at 15:10
  • @EdHeal, man backtrace suggested void** as the first argument. Commented Feb 24, 2018 at 15:11

3 Answers 3

4

what about a loop where you'd format the pointer in a temporary buffer (with leading space), then concatenate it with the command prefix:

int size = backtrace(buffer, 10);
char cmd[1024] = "addr2line -f -p -e a.out";
char buf[20]; // should be enough to hold pointer value
int i;
for (i = 0; i < size; i++)
{
   sprintf(buf," %p",buffer[i]);
   // you could even check the size here in case cmd+buf overflows cmd size
   strcat(cmd,buf);
}

or for performance purists, since strcat computes the length every time, we could use the return value of sprintf to print in the buffer directly. Slightly more complex but avoids the quadratic string length computation effect:

char cmd[1024] = "addr2line -f -p -e a.out";
int i;
char *current = cmd + strlen(cmd);
for (i = 0; i < size; i++)
{
   int nb_written = sprintf(current," %p",buffer[i]);
   if (current+nb_written > cmd+sizeof(cmd)) break;  // avoids buffer overflow
   current += nb_written;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I see what you mean, it's not optimal in terms of performance / quadratic. That could be improved with pointers, yes
shoot, just edited to the same solution as yours (well almost)
2

Use a loop. sprintf() returns the number of written characters or -1:


void *buffer[10];
char cmd[1024];
int size,idx;
size_t pos, len;

size = backtrace(buffer, 10);
pos = sprintf(cmd, "addr2line -f -p -e a.out");
for(idx=0 ; idx< size;idx++){
        len = sprintf(cmd+pos, " %p", buffer[idx] );
        if (len<0 || len+pos >= sizeof cmd) break;
        pos += len;
        }

Or, if you want to respect the size of cmd[], use snprintf():


#include <stdio.h>
int backtrace(void**, int);

void joop(void)
{

void *buffer[10];
char cmd[1024];
int size,idx;
size_t pos, len;

size = backtrace(buffer, 10);
pos= snprintf(cmd,sizeof cmd, "addr2line -f -p -e a.out");
for(idx=0 ; idx < size; idx++){
        len = snprintf(cmd+pos, sizeof cmd - pos, " %p", buffer[idx] );
        if (len < 0 || len+pos >= sizeof cmd) break;
        pos += len;
        }
}

2 Comments

You could use len = snprintf(cmd + pos, sizeof(cmd) -pos, " %p", buffer[idx]); and a different error check to prevent buffer overflow, could you not?
@JonathanLeffler: Yes, I was just adding the snprintf() thingy.
1

If the maximum size of the array is explicitly capped at 10, you can get away with a very minor modification: simply trim your format string at the appropriate point

void *buffer[10];
int size = backtrace(buffer, 10);

char format[] = "addr2line -f -p -e a.out %p %p %p %p %p %p %p %p %p %p";
format[24 + size * 3] = '\0';

char cmd[1024];
sprintf(cmd, format,
    buffer[0],
    buffer[1],
    buffer[2],
    buffer[3],
    buffer[4],
    buffer[5],
    buffer[6],
    buffer[7],
    buffer[8],
    buffer[9]
);

There's nothing wrong in supplying excessive variadic arguments to a variadic function.

Of course, the exact spot for inserting that '\0' should be calculated in a more readabale and maintainable way, not by using "magic constants" as in my example above.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.