Potheker
Potheker

Reputation: 95

Segmentation fault when using setenv (C)

This is a part of my code (where max is a float):

        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");

Which produces the output:

noise level found: 2410965368832.000000
Segmentation fault

While some lines earlier I have almost the same:

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);

Which works without a problem.

//EDIT: Changed Arraysize, sadly didn't fix problem

Upvotes: 1

Views: 797

Answers (2)

Kurtis Rader
Kurtis Rader

Reputation: 7469

Never, ever, use functions like sprintf() and strcpy() which do not take an argument that specifies the size of the buffer. Always use snprintf(), strlcpy(), etc. and check the return value for errors. That way, if the buffer is too small you can handle it rather than just assuming that scribbling on random memory locations past the end of your buffer won't cause any problems. As @chux noted what you're doing results in undefined behavior. Also known as a halt and catch fire (HCF) situation.

Also, note that this isn't due to anything setenv() is doing. The bug is that sprintf() is writing past the end of the buffer you gave it. Literally anything you do after that sprintf() call could fail. Including simply returning from the function that did that sprintf() call.

Upvotes: -2

chux
chux

Reputation: 154169

A insufficient size buffer is undefined behavior (UB). That UB may show itself in places far from the original UB.

Improve code by writing code that will not overrun the buffer - everywhere and for all values.

Provide adequate buffer for all 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);

Use snprint() to avoid buffer overflow @R..

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

Robust code would check the return value:

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

Use "%e" to cope with and well present large and small floating point values

Use exponential notation to avoid large buffers. Use enough precision.

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);

Upvotes: 3

Related Questions