Browse Source

Replace bfg_sprintf with safer bfg_snprintf

Luke Dashjr 12 years ago
parent
commit
bf8aebd08e
3 changed files with 100 additions and 71 deletions
  1. 22 18
      miner.c
  2. 52 45
      util.c
  3. 26 8
      util.h

+ 22 - 18
miner.c

@@ -2457,9 +2457,12 @@ void pick_unit(float hashrate, unsigned char *unit)
 
 static const size_t h2bs_fmt_size[] = {6, 10, 11};
 
-char *format_unit(char *buf, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float hashrate, signed char unitin)
+int format_unit2(char *buf, size_t sz, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float hashrate, signed char unitin)
 {
+	char *s = buf;
 	unsigned char prec, i, unit;
+	int rv = 0;
+	
 	if (unitin == -1)
 	{
 		unit = 0;
@@ -2477,27 +2480,24 @@ char *format_unit(char *buf, bool floatprec, const char *measurement, enum h2bs_
 			prec = 1;
 		else
 			prec = 2;
-		sprintf(buf, "%5.*f", prec, hashrate);
-		i = 5;
+		_SNP("%5.*f", prec, hashrate);
 	}
 	else
-	{
-		sprintf(buf, "%3d", (int)hashrate);
-		i = 3;
-	}
+		_SNP("%3d", (int)hashrate);
 	
 	switch (fmt) {
 	case H2B_SPACED:
-		buf[i++] = ' ';
+		_SNP(" ");
 	case H2B_SHORT:
-		buf[i++] = _unitchar[unit];
-		strcpy(&buf[i], measurement);
+		_SNP("%c%s", _unitchar[unit], measurement);
 	default:
 		break;
 	}
 	
-	return buf;
+	return rv;
 }
+#define format_unit(buf, floatprec, measurement, fmt, rate, unitin)  \
+	(void)format_unit2(buf, SSIZE_MAX, floatprec, measurement, fmt, rate, unitin);
 
 static
 char *_multi_format_unit(char **buflist, bool floatprec, const char *measurement, enum h2bs_fmt fmt, const char *delim, int count, const float *numbers, bool isarray)
@@ -2536,28 +2536,32 @@ char *_multi_format_unit(char **buflist, bool floatprec, const char *measurement
 #define multi_format_unit(buf, floatprec, measurement, fmt, delim, count, ...)  _multi_format_unit((char *[]){buf}, floatprec, measurement, fmt, delim, count, (float[]){ __VA_ARGS__ }, false)
 #define multi_format_unit_array(buflist, floatprec, measurement, fmt, count, ...)  (void)_multi_format_unit(buflist, floatprec, measurement, fmt, NULL, count, (float[]){ __VA_ARGS__ }, true)
 
-void percentf3(char * const buf, double p, const double t)
+int percentf3(char * const buf, size_t sz, double p, const double t)
 {
+	char *s = buf;
+	int rv = 0;
 	if (!p)
-		strcpy(buf, "none");
+		_SNP("none");
 	else
 	if (t <= p)
-		strcpy(buf, "100%");
+		_SNP("100%%");
 	else
 	{
 
 	p /= t;
 	if (p < 0.01)
-		sprintf(buf, ".%02.0f%%", p * 10000);  // ".01%"
+		_SNP(".%02.0f%%", p * 10000);  // ".01%"
 	else
 	if (p < 0.1)
-		sprintf(buf, "%.1f%%", p * 100);  // "9.1%"
+		_SNP("%.1f%%", p * 100);  // "9.1%"
 	else
-		sprintf(buf, "%3.0f%%", p * 100);  // " 99%"
+		_SNP("%3.0f%%", p * 100);  // " 99%"
 
 	}
+	
+	return rv;
 }
-#define percentf2(p, t, buf)  (percentf3(buf, p, t), buf)
+#define percentf2(p, t, buf)  (percentf3(buf, SIZE_MAX, p, t), buf)
 #define percentf(p, t, buf)  percentf2(p, p + t, buf)
 
 #ifdef HAVE_CURSES

+ 52 - 45
util.c

@@ -1240,7 +1240,7 @@ void bfg_init_time()
 }
 
 // NOTE: Only supports (BTF_BRACKETS | BTF_DATE | BTF_TIME) for now
-int format_elapsed(char * const buf, const int fmt, int elapsed)
+int format_elapsed2(char * const buf, size_t sz, const int fmt, int elapsed)
 {
 	unsigned int days, hours;
 	div_t d;
@@ -1251,7 +1251,7 @@ int format_elapsed(char * const buf, const int fmt, int elapsed)
 	hours = d.quot;
 	d = div(d.rem, 60);
 	return
-	sprintf(buf, "[%3u day%c %02d:%02d:%02d]"
+	snprintf(buf, sz, "[%3u day%c %02d:%02d:%02d]"
 		, days
 		, (days == 1) ? ' ' : 's'
 		, hours
@@ -1260,52 +1260,45 @@ int format_elapsed(char * const buf, const int fmt, int elapsed)
 	);
 }
 
-int format_tm(char * const buf, const int fmt, const struct tm * const tm, const long usecs)
+int format_tm2(char * const buf, size_t sz, const int fmt, const struct tm * const tm, const long usecs)
 {
 	char *s = buf;
+	int rv = 0;
 	
 	if (fmt & BTF_BRACKETS)
-		(s++)[0] = '[';
+		_SNP("[");
 	if (fmt & BTF_DATE)
-	{
-		s +=
-		sprintf(s, "%d-%02d-%02d",
+		_SNP("%d-%02d-%02d%s",
 		        tm->tm_year + 1900,
 		        tm->tm_mon + 1,
-		        tm->tm_mday);
-		if (fmt & 3 /* any time */)
-			(s++)[0] = ' ';
-	}
+		        tm->tm_mday,
+		     (fmt & 3 /* any time */) ? " " : "");
 	if (fmt & 3 /* any time */)
 	{
-		s +=
-		sprintf(s, "%02d:%02d",
+		_SNP("%02d:%02d",
 		        tm->tm_hour,
 		        tm->tm_min);
 		if (fmt & 1 /* with seconds */)
 		{
-			s +=
-			sprintf(s, ":%02d", tm->tm_sec);
+			_SNP(":%02d", tm->tm_sec);
 			if ((fmt & BTF_HRTIME) == BTF_HRTIME)
-				s +=
-				sprintf(s, ".%06ld", usecs);
+				_SNP(".%06ld", usecs);
 		}
 	}
 	if (fmt & BTF_BRACKETS)
-		s +=
-		sprintf(s, "]");
+		_SNP("]");
 	
-	return (s - buf);
+	return rv;
 }
 
-int format_timestamp(char * const buf, const int fmt, const struct timeval * const tv)
+int format_timestamp2(char * const buf, size_t sz, const int fmt, const struct timeval * const tv)
 {
 	struct tm tm;
 	time_t tt = tv->tv_sec;
 	
 	localtime_r(&tt, &tm);
 	
-	return format_tm(buf, fmt, &tm, tv->tv_usec);
+	return format_tm2(buf, sz, fmt, &tm, tv->tv_usec);
 }
 
 void subtime(struct timeval *a, struct timeval *b)
@@ -1445,10 +1438,10 @@ void utf8_test()
 }
 
 
-int format_temperature(char * const buf, const int pad, const bool highprecision, const bool unicode, const float temp)
+int format_temperature2(char * const buf, size_t sz, const int pad, const bool highprecision, const bool unicode, const float temp)
 {
 	return
-	sprintf(buf, "%*.*f%sC"
+	snprintf(buf, sz, "%*.*f%sC"
 	        , pad
 	        , (highprecision ? 1 : 0)
 	        , temp
@@ -1462,7 +1455,7 @@ int format_temperature_sz(const int numsz, const bool unicode)
 }
 
 
-int bfg_vsprintf(char * const buf, const char *fmt, va_list ap)
+int bfg_vsnprintf(char * const buf, size_t sz, const char *fmt, va_list ap)
 {
 	char *s = buf;
 	size_t L;
@@ -1471,6 +1464,7 @@ int bfg_vsprintf(char * const buf, const char *fmt, va_list ap)
 	long arg_ld;
 	int64_t arg_d64;
 	double arg_f, arg_f_2;
+	int rv = 0;
 	
 	for (const char *p = fmt; ; ++p)
 	{
@@ -1484,7 +1478,7 @@ int bfg_vsprintf(char * const buf, const char *fmt, va_list ap)
 					char fmtcp[L+1];
 					memcpy(fmtcp, fmt, L);
 					fmtcp[L] = '\0';
-					s += vsprintf(s, fmtcp, ap);
+					_SNP2(vsnprintf, fmtcp, ap);
 					fmt += L;
 				}
 				if (!fmt[0])
@@ -1498,25 +1492,25 @@ switch (fmt[1])
 		arg_d = va_arg(ap, int);
 		arg_p = va_arg(ap, void*);
 		arg_ld = va_arg(ap, long);
-		s += format_tm(s, arg_d, arg_p, arg_ld);
+		_SNP2(format_tm2, arg_d, arg_p, arg_ld);
 		L = sizeof(BPRItm);
 		break;
 	case 2:  // format_timestamp
 		arg_d = va_arg(ap, int);
 		arg_p = va_arg(ap, void*);
-		s += format_timestamp(s, arg_d, arg_p);
+		_SNP2(format_timestamp2, arg_d, arg_p);
 		L = sizeof(BPRIts);
 		break;
 	case 3:  // format_time_t
 		arg_d = va_arg(ap, int);
 		arg_d64 = va_arg(ap, int64_t);
-		s += format_time_t(s, arg_d, arg_d64);
+		_SNP2(format_time_t2, arg_d, arg_d64);
 		L = sizeof(BPRItt);
 		break;
 	case 4:  // format_elapsed
 		arg_d = va_arg(ap, int);
 		arg_d_2 = va_arg(ap, int);
-		s += format_elapsed(s, arg_d, arg_d_2);
+		_SNP2(format_elapsed2, arg_d, arg_d_2);
 		L = sizeof(BPRIte);
 		break;
 	case 5:  // format_unit (int-precision)
@@ -1525,13 +1519,12 @@ switch (fmt[1])
 		arg_d = va_arg(ap, int);
 		arg_f = va_arg(ap, double);
 		arg_d_2 = va_arg(ap, int);
-		format_unit(s, (fmt[1] == 6), arg_p, arg_d, arg_f, arg_d_2);
-		s += strlen(s);
+		_SNP2(format_unit2, (fmt[1] == 6), arg_p, arg_d, arg_f, arg_d_2);
 		L = sizeof(BPRInd);
 		break;
 	case 7:  // temperature
 		arg_f = va_arg(ap, double);
-		s += format_temperature(s, 0, false, true, arg_f);
+		_SNP2(format_temperature2, 0, false, true, arg_f);
 		L = sizeof(BPRItp);
 		break;
 	case 8:  // percentage, 2nd arg is OTHERS
@@ -1540,8 +1533,7 @@ switch (fmt[1])
 		arg_f_2 = va_arg(ap, double);
 		if (fmt[1] == 8)
 			arg_f_2 += arg_f;
-		percentf3(s, arg_f, arg_f_2);
-		s += 4;
+		_SNP2(percentf3, arg_f, arg_f_2);
 		L = sizeof(BPRIpgo);
 		break;
 }
@@ -1555,11 +1547,11 @@ switch (fmt[1])
 	}
 }
 
-int bfg_sprintf(char * const buf, const char * const fmt, ...)
+int bfg_snprintf(char * const buf, size_t sz, const char * const fmt, ...)
 {
 	va_list ap;
 	va_start(ap, fmt);
-	int rv = bfg_vsprintf(buf, fmt, ap);
+	int rv = bfg_vsnprintf(buf, sz, fmt, ap);
 	va_end(ap);
 	return rv;
 }
@@ -1567,20 +1559,35 @@ int bfg_sprintf(char * const buf, const char * const fmt, ...)
 static
 void _test_bfg_sprintf(const char * const testname, const char * const fmt, const char * const expected, ...)
 {
-	char buf[0x100];
 	int len = strlen(expected), rv;
+	char buf[len + 3];
 	
-	va_list ap;
+	va_list ap, ap2;
 	va_start(ap, expected);
-	rv = bfg_vsprintf(buf, fmt, ap);
-	va_end(ap);
+	buf[len + 2] = '\0';
+	
+	// NOTE: Some systems error on 0-sized buffers :(
+	for (int i = 1; i < len + 2; ++i)
+	{
+		memset(buf, 'X', len + 2);
+		va_copy(ap2, ap);
+		rv = bfg_vsnprintf(buf, i, fmt, ap2);
+		va_end(ap2);
+		
+		if ( (len != rv)  // Return value must be full length
+		  || ((i > 1) ? memcmp(buf, expected, i - 1) : 0)  // Data before end point must match expectations
+		  || (buf[i - 1]) )  // Final byte in buffer must be null
+			applog(LOG_WARNING, "bfg_snprintf test %s/%d failed: returned %d bytes \"%s\" with size %d", testname, i, strlen(buf), buf, rv);
+	}
 	
-	if (len != rv || memcmp(buf, expected, len))
-		applog(LOG_WARNING, "bfg_sprintf test %s failed: returned %d bytes \"%s\"", testname, rv, buf);
+	// Check extra buffer
+	rv = bfg_vsnprintf(buf, len + 2, fmt, ap2);
+	if (len != rv || memcmp(buf, expected, len + 1))
+		applog(LOG_WARNING, "bfg_snprintf test %s/x failed: returned %d bytes \"%s\" with size %d", testname, strlen(buf), buf, rv);
 }
 #define _test_bfg_sprintf(fmt, ...)  _test_bfg_sprintf(#fmt, fmt, __VA_ARGS__)
 
-void test_bfg_sprintf()
+void test_bfg_snprintf()
 {
 	struct tm tm = {
 		.tm_year = 115,
@@ -1650,7 +1657,7 @@ void test_bfg_sprintf()
 	_test_bfg_sprintf("a"BPRInf"bcB", "a 1.00Gx/ybcB", "x/y", H2B_SHORT, 1e9, -1);
 	_test_bfg_sprintf("a"BPRInf"bcC", "a 1.00Tx/ybcC", "x/y", H2B_SHORT, 1e12, -1);
 	
-	_test_bfg_sprintf("a"BPRItp"bc", "a80\xb0""Cbc", 80.);
+	_test_bfg_sprintf("a"BPRItp"bc", "a80"U8_DEGREE"Cbc", 80.);
 	
 	_test_bfg_sprintf("a"BPRIpgo"bc1", "anonebc1",  0.,  40.);
 	_test_bfg_sprintf("a"BPRIpgo"bc2", "a100%bc2", 10.,   0.);

+ 26 - 8
util.h

@@ -308,10 +308,17 @@ enum timestamp_format {
 	BTF_BRACKETS = 0x10,
 };
 
-extern int format_elapsed(char * const buf, const int fmt, int elapsed);
-extern int format_tm(char * const buf, const int fmt, const struct tm * const, const long usecs);
-extern int format_timestamp(char * const buf, const int fmt, const struct timeval * const);
+extern int format_elapsed2(char * const buf, size_t sz, const int fmt, int elapsed);
+#define format_elapsed(buf, fmt, elapsed)  \
+	format_elapsed2(buf, SIZE_MAX, fmt, elapsed)
+extern int format_tm2(char * const buf, size_t sz, const int fmt, const struct tm * const, const long usecs);
+#define format_tm(buf, fmt, tm, usecs)  \
+	format_tm2(buf, SIZE_MAX, fmt, tm, usecs)
+extern int format_timestamp2(char * const buf, size_t sz, const int fmt, const struct timeval * const);
+#define format_timestamp(buf, fmt, tv)  \
+	format_timestamp2(buf, SIZE_MAX, fmt, tv)
 #define format_time_t(buf, fmt, tt)  format_timestamp(buf, fmt, (struct timeval[1]){ { .tv_sec = tt } })
+#define format_time_t2(buf, sz, fmt, tt)  format_timestamp2(buf, sz, fmt, (struct timeval[1]){ { .tv_sec = tt } })
 #define get_datestamp(buf, tt)  format_time_t(buf, BTF_DATE | BTF_TIME | BTF_BRACKETS, tt)
 #define get_now_datestamp(buf)  get_datestamp(buf, time(NULL))
 #define get_timestamp(buf, tt)  format_time_t(buf, BTF_TIME | BTF_BRACKETS, tt)
@@ -353,9 +360,20 @@ enum h2bs_fmt {
 extern int32_t utf8_decode(const void *, int *out_len);
 extern void utf8_test();
 
-extern char *format_unit(char *buf, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float n, signed char unitin);
-extern void percentf3(char * const buf, double p, const double t);
-extern int format_temperature(char * const buf, const int pad, const bool highprecision, const bool unicode, const float temp);
+#define _SNP2(fn, ...)  do{  \
+	int __n42 = fn(s, sz, __VA_ARGS__);  \
+	s += __n42;  \
+	sz -= __n42;  \
+	rv += __n42;  \
+}while(0)
+
+#define _SNP(...)  _SNP2(snprintf, __VA_ARGS__)
+
+extern int format_unit2(char *buf, size_t, bool floatprec, const char *measurement, enum h2bs_fmt fmt, float n, signed char unitin);
+extern int percentf3(char * const buf, size_t, double p, const double t);
+extern int format_temperature2(char * const buf, size_t, const int pad, const bool highprecision, const bool unicode, const float temp);
+#define format_temperature(buf, pad, highprecision, unicode, temp)  \
+	format_temperature2(buf, SIZE_MAX, pad, highprecision, unicode, temp)
 extern int format_temperature_sz(const int numsz, const bool unicode);
 
 #define BPRItm "\b\x01%d%p%ld"
@@ -369,9 +387,9 @@ extern int format_temperature_sz(const int numsz, const bool unicode);
 #define BPRIpgt "\b\x09%f%f"
 
 #ifdef va_arg
-extern int bfg_vsprintf(char * const buf, const char *fmt, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
+extern int bfg_vsnprintf(char * const buf, size_t, const char *fmt, va_list ap) FORMAT_SYNTAX_CHECK(printf, 3, 0);
 #endif
-extern int bfg_sprintf(char * const buf, const char * const fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
+extern int bfg_snprintf(char * const buf, size_t, const char * const fmt, ...) FORMAT_SYNTAX_CHECK(printf, 3, 4);
 extern void test_bfg_sprintf();