2015-10-23 2 views
2

Это существующий код, который находит относительный путь, соответствующий родительскому пути. Он работает как ожидается на платформах, кроме SUSE 12 с GCC 4.7. Я упомянул о некорректном выходе и ожидал в комментариях. Я пытаюсь понять, почему это происходит?Что не так с этим кодом? И дочерняя, и родительская строки заканчиваются символом NUL. Единственное, что я вижу, это то, что источник и получатель передаются из одного и того же места в памяти, другими словами, мы пытаемся обновить значение того же места в памяти. Это настоящая проблема?Что-то не так с stpncpy() здесь?

//child = /dev/shm/4/tmp/backup/datadir/performance_schema/events_stages_summary_by_account_by_event_name.frm 
//parent = /dev/shm/4/tmp/backup 

char* get_relative_path(char *child, const char *parent) 
{ 
    char* start= child; 
    static char dot[] = "." ; 

    .... 
    .... 

    /* Check if child = parent + "/" + .... */ 
    if (strstr(child, parent) == child) 
    { 
     int parent_len= strlen(parent); 

     /* parent path may or may not have the "/" suffix. check for both. */ 
     if (parent[parent_len-1] == FN_LIBCHAR || 
      child[parent_len] == FN_LIBCHAR) 
     { 
      child+= parent_len; 
      while (*child && *child == FN_LIBCHAR) 
       child++; 
      if (*child == 0) 
       return dot; 
     } 
    } 
    // At this point the value of 
    // start = /dev/shm/4/tmp/backup/datadir/performance_schema/events_stages_summary_by_account_by_event_name.frm 
    // child = datadir/performance_schema/events_stages_summary_by_account_by_event_name.frm 

    if(start != child) 
    { 
     stpncpy(start, child, PATH_MAX); 
    } 

    // At this point expected value of start = datadir/performance_schema/events_stages_summary_by_account_by_event_name.frm 
    // But actual value of start = datadir/performance_schenamevents_stages_summary_by_account_by_event_name.frm 

    return start; 
} 
+3

Man страница stpncpy говорит струны могут ** не ** перекрываются. Вы могли бы решить эту проблему, выполнив функцию, которая начинается назад и, следовательно, не будет считываться из уже записанного местоположения. Я не знаю, действительно ли это настоящая проблема, если взглянуть на это очень быстро, но это одна из потенциальных проблем. – Jite

+0

Хорошо ... jite и @mch указали на ту же проблему – Rahul

ответ

5

От Человека Странице stpncpy: The strings may not overlap.

Таким образом, вы должны использовать memmove, в противном случае поведение не определено.

stpncpy(start, child, PATH_MAX); должен быть
memmove(start, child, PATH_MAX > strlen(child) + 1? strlen(child) + 1: PATH_MAX);

Вы должны также иметь в виду, что stpncpy очень неэффективно, если вы используете маленькие ниточки на больших массивах, так как он будет писать n символы каждый раз. В вашем случае он напишет около 4000 '\0' после вашей строки.
Человек Страница говорит

Точно п символы записываются в Dest. Если длина STRLEN (ЦСИ) меньше, чем п, остальные символы в массиве, на который указывает Dest заполняются нулевыми байтами («\ 0»)

+0

Код, упомянутый выше, отлично работал годами, но внезапно мы начали видеть эту проблему. хм .. но я вижу вашу точку ** может ** кажется виновником в предложении «Строка не перекрывается», упомянутой на странице руководства. – Rahul

+0

Позвольте мне попробовать ваше решение, когда это будет работать, я буду отмечать его как ответ. Поэтому фактический ответ на мой вопрос заключается в том, что использование stpncpy(), strcpy(), strncpy() небезопасно, если память перекрывается. – Rahul

+0

Использование этой функции при перекрытии строк может привести к неопределенному поведению, которое включает в себя как «работает как ожидалось», так и «... кроме здесь». Независимо от того, работает оно или нет, зависит от реализации функции; и реализации могут различаться в разных библиотеках для разных компиляторов и/или платформ. – usr2564301

Смежные вопросы