comparison src/utils.cc @ 13991:051a8f94b6f8

avoid memory issue with octave_vsnprintf * utils.h, utils.cc (octave_vsnprintf, octave_snprintf): Return std::string, not char *. (octave_vformat, octave_format): Return size_t, not int. (octave_vsnprintf): Simplify implementation with vasprintf. Include gnulib vasprintf.h from gnulib. * bootstrap.conf (gnulib_modules): Include vasprintf in the list.
author John W. Eaton <jwe@octave.org>
date Sun, 04 Dec 2011 15:57:58 -0500
parents 6ead4dc1ca55
children f8556baf1949
comparison
equal deleted inserted replaced
13990:c9a0e5343cd8 13991:051a8f94b6f8
33 #include <iostream> 33 #include <iostream>
34 #include <string> 34 #include <string>
35 35
36 #include <sys/types.h> 36 #include <sys/types.h>
37 #include <unistd.h> 37 #include <unistd.h>
38
39 #include "vasnprintf.h"
38 40
39 #include "quit.h" 41 #include "quit.h"
40 42
41 #include "dir-ops.h" 43 #include "dir-ops.h"
42 #include "file-ops.h" 44 #include "file-ops.h"
1192 } 1194 }
1193 1195
1194 return m; 1196 return m;
1195 } 1197 }
1196 1198
1197 int 1199 size_t
1198 octave_format (std::ostream& os, const char *fmt, ...) 1200 octave_format (std::ostream& os, const char *fmt, ...)
1199 { 1201 {
1200 int retval = -1; 1202 size_t retval;
1201 1203
1202 va_list args; 1204 va_list args;
1203 va_start (args, fmt); 1205 va_start (args, fmt);
1204 1206
1205 retval = octave_vformat (os, fmt, args); 1207 retval = octave_vformat (os, fmt, args);
1207 va_end (args); 1209 va_end (args);
1208 1210
1209 return retval; 1211 return retval;
1210 } 1212 }
1211 1213
1212 int 1214 size_t
1213 octave_vformat (std::ostream& os, const char *fmt, va_list args) 1215 octave_vformat (std::ostream& os, const char *fmt, va_list args)
1214 { 1216 {
1215 int retval = -1; 1217 std::string s = octave_vsnprintf (fmt, args);
1216 1218
1217 #if defined (__GNUG__) && !CXX_ISO_COMPLIANT_LIBRARY 1219 os << s;
1218 1220
1219 std::streambuf *sb = os.rdbuf (); 1221 return s.length ();
1220 1222 }
1221 if (sb) 1223
1222 { 1224 std::string
1223 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1224
1225 retval = sb->vform (fmt, args);
1226
1227 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1228 }
1229
1230 #else
1231
1232 char *s = octave_vsnprintf (fmt, args);
1233
1234 if (s)
1235 {
1236 os << s;
1237
1238 retval = strlen (s);
1239 }
1240
1241 #endif
1242
1243 return retval;
1244 }
1245
1246 // We manage storage. User should not free it, and its contents are
1247 // only valid until next call to vsnprintf.
1248
1249 // Interrupts might happen if someone makes a call with something that
1250 // will require a very large buffer. If we are interrupted in that
1251 // case, we should make the buffer size smaller for the next call.
1252
1253 #define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF \
1254 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_1; \
1255 delete [] buf; \
1256 buf = 0; \
1257 size = initial_size; \
1258 octave_rethrow_exception (); \
1259 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_2
1260
1261 #if defined __GNUC__ && defined __va_copy
1262 #define SAVE_ARGS(saved_args, args) __va_copy (saved_args, args)
1263 #elif defined va_copy
1264 #define SAVE_ARGS(saved_args, args) va_copy (saved_args, args)
1265 #else
1266 #define SAVE_ARGS(saved_args, args) saved_args = args
1267 #endif
1268
1269 char *
1270 octave_vsnprintf (const char *fmt, va_list args) 1225 octave_vsnprintf (const char *fmt, va_list args)
1271 { 1226 {
1272 static const size_t initial_size = 100; 1227 std::string retval;
1273 1228
1274 static size_t size = initial_size; 1229 char *result;
1275 1230
1276 static char *buf = 0; 1231 int status = vasprintf (&result, fmt, args);
1277 1232
1278 volatile int nchars = 0; 1233 if (status >= 0)
1279 1234 {
1280 if (! buf) 1235 retval = result;
1281 buf = new char [size]; 1236 ::free (result);
1282 1237 }
1283 if (! buf) 1238
1284 return 0; 1239 return retval;
1285 1240 }
1286 while (1) 1241
1287 { 1242 std::string
1288 va_list saved_args;
1289
1290 SAVE_ARGS (saved_args, args);
1291
1292 BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF;
1293
1294 nchars = octave_raw_vsnprintf (buf, size, fmt, saved_args);
1295
1296 va_end (saved_args);
1297
1298 END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE;
1299
1300 // Cast to avoid signed/unsigned comparison is safe due to
1301 // short-circuiting
1302 if (nchars > -1 && static_cast<size_t>(nchars) < size)
1303 break;
1304 else
1305 {
1306 delete [] buf;
1307
1308 size = nchars + 1;;
1309
1310 buf = new char [size];
1311
1312 if (! buf)
1313 return 0;
1314 }
1315 }
1316
1317 return buf;
1318 }
1319
1320 char *
1321 octave_snprintf (const char *fmt, ...) 1243 octave_snprintf (const char *fmt, ...)
1322 { 1244 {
1323 char *retval = 0; 1245 std::string retval;
1324 1246
1325 va_list args; 1247 va_list args;
1326 va_start (args, fmt); 1248 va_start (args, fmt);
1327 1249
1328 retval = octave_vsnprintf (fmt, args); 1250 retval = octave_vsnprintf (fmt, args);