Ошибка сегментации при использовании setenv (C) - PullRequest
1 голос
/ 13 февраля 2020

Это часть моего кода (где max - это число с плавающей запятой):

        printf("noise level found: %f\n", max);

        //Put into "String"
        char var[21];
        sprintf(var, "%f", max);

        setenv("music_sync_soundcard_noise_level",var,1);

        printf("noise level written\n");

, который выдает результат:

noise level found: 2410965368832.000000
Segmentation fault

Хотя некоторые строки ранее у меня почти одинаковы :

printf("test finished, offset is %f\n", *offset);

//Put into "String"
char var[20];
sprintf(var, "%f", *offset);

setenv("music_sync_soundcard_offset",var,1);

, который работает без проблем.

// РЕДАКТИРОВАТЬ: изменил размер массива, к сожалению, не решил проблему

Ответы [ 2 ]

3 голосов
/ 13 февраля 2020

Недостаточный размер буфера: неопределенное поведение (UB). Этот UB может отображаться в местах, далеких от исходного UB.

Улучшение кода путем написания кода, который не будет переполнять буфер - везде и для всех значений.

Обеспечить достаточный буфер для все max

#include <float.h>

float max;    
// char var[21];
char var[1 + 1+FLT_MAX_10_EXP                             + 1 + 6      + 1];
//       -   d dddddddddd dddddddddd dddddddddd dddddddd    .   fraction \0
sprintf(var, "%f", max);

Используйте snprint(), чтобы избежать переполнения буфера @ R ..

// sprintf(var, "%f", max);
snprintf(var, sizeof var, "%f", max);

Надежный код проверяет возвращаемое значение:

int len = snprintf(var, sizeof var, "%f", max);
if (len < 0 || (unsigned) len >= sizeof var) Oops();

Используйте "%e", чтобы справляться с большими и малыми значениями с плавающей запятой и хорошо представлять их

Используйте экспоненциальную запись, чтобы избежать больших буферов. Используйте достаточную точность.

char var[1 + 1 + 1 + FLT_DECIMAL_DIG-1 + 1 + 1 + 4 + 1];
//       -   d   .   dddddddd            e   -  expo \0
sprintf(var, sizeof var, "%.*e", FLT_DECIMAL_DIG-1, max);
0 голосов
/ 14 февраля 2020

Никогда, никогда не используйте такие функции, как sprintf() и strcpy(), которые не принимают аргумент, который определяет размер буфера. Всегда используйте snprintf(), strlcpy(), et c. и проверьте возвращаемое значение на наличие ошибок. Таким образом, если буфер слишком мал, вы можете справиться с ним, а не просто предполагать, что рисование в произвольных местах памяти за концом буфера не вызовет никаких проблем. Как заметил @chux, то, что вы делаете, приводит к неопределенному поведению. Также известна как остановка и загорание (HCF) ситуация.

Также обратите внимание, что это не из-за того, что делает setenv(). Ошибка в том, что sprintf() пишет после конца буфера, который вы ему дали. Буквально все, что вы делаете после этого sprintf() вызова, может потерпеть неудачу. Включая простой возврат из функции, которая выполняла этот вызов sprintf().

...