Mercurial > octave-nkf
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); |