Parcourir la source

[master] Merge branch 'trac2272'

Marcin Siodelski il y a 12 ans
Parent
commit
f406d515e8

+ 20 - 0
configure.ac

@@ -1074,6 +1074,26 @@ if test "x$VALGRIND" != "xno"; then
    found_valgrind="found"
 fi
 
+# Check for optreset in unistd.h. On BSD systems the optreset is
+# used to reset the state of getopt() function. Resetting its state
+# is required if command line arguments are parsed multiple times
+# during a program. On Linux this variable will not exist because
+# getopt() reset is performed by setting optind = 0. On Operating
+# Systems where optreset is defined use optreset = 1 and optind = 1
+# to reset internal state of getopt(). Failing to do so will result
+# in unpredictable output from getopt().
+AC_MSG_CHECKING([whether optreset variable is defined in unistd.h])
+AC_TRY_LINK(
+    [#include <unistd.h>],
+    [extern int optreset; optreset=1;],
+    [ AC_MSG_RESULT(yes)
+      var_optreset_exists=yes],
+    [ AC_MSG_RESULT(no)
+      var_optreset_exists=no]
+)
+AM_CONDITIONAL(HAVE_OPTRESET, test "x$var_optreset_exists" != "xno")
+AM_COND_IF([HAVE_OPTRESET], [AC_DEFINE([HAVE_OPTRESET], [1], [Check for optreset?])])
+
 AC_CONFIG_FILES([Makefile
                  doc/Makefile
                  doc/guide/Makefile

+ 9 - 0
tests/tools/perfdhcp/command_options.cc

@@ -113,6 +113,15 @@ CommandOptions::parse(int argc, char** const argv) {
     optind = 1;
 #endif
 
+    // optreset is declared on BSD systems and is used to reset internal
+    // state of getopt(). When parsing command line arguments multiple
+    // times with getopt() the optreset must be set to 1 every time before
+    // parsing starts. Failing to do so will result in random behavior of
+    // getopt().
+#ifdef HAVE_OPTRESET
+    optreset = 1;
+#endif
+
     opterr = 0;
 
     // Reset values of class members

+ 8 - 8
tests/tools/perfdhcp/tests/command_options_helper.h

@@ -57,10 +57,10 @@ public:
         ~ArgvPtr() {
             if (argv_ != NULL) {
                 for(int i = 0; i < argc_; ++i) {
-                    free(argv_[i]);
+                    delete[] (argv_[i]);
                     argv_[i] = NULL;
                 }
-                free(argv_);
+                delete[] (argv_);
             }
         }
 
@@ -102,6 +102,7 @@ private:
     ///
     /// \param text_to_split string to be splited.
     /// \param [out] num number of substrings returned.
+    /// \param std::bad_alloc if allocation of C-strings failed.
     /// \return array of C-strings created from split.
     static char** tokenizeString(const std::string& text_to_split, int& num) {
         char** results = NULL;
@@ -115,14 +116,13 @@ private:
 
         if (tokens.size() > 0) {
             // Allocate array of C-strings where we will store tokens
-            results = static_cast<char**>(malloc(tokens.size() * sizeof(char*)));
-            if (results == NULL) {
-                isc_throw(Unexpected, "unable to allocate array of c-strings");
-            }
+            results = new char*[tokens.size()];
             // Store tokens in C-strings array
             for (int i = 0; i < tokens.size(); ++i) {
-                char* cs = static_cast<char*>(malloc(tokens[i].length() + 1));
-                strcpy(cs, tokens[i].c_str());
+                size_t cs_size = tokens[i].length() + 1;
+                char* cs = new char[cs_size];
+                strncpy(cs, tokens[i].c_str(), cs_size);
+                assert(cs[cs_size - 1] == '\0');
                 results[i] = cs;
             }
             // Return number of tokens to calling function