Print this page
12364 mdb trips assertion related to autowrap

@@ -22,11 +22,11 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 /*
- * Copyright (c) 2019, Joyent, Inc. All rights reserved.
+ * Copyright 2020 Joyent, Inc.
  * Copyright (c) 2016 by Delphix. All rights reserved.
  */
 
 /*
  * MDB uses its own enhanced standard i/o mechanism for all input and output.

@@ -1775,10 +1775,31 @@
         va_end(alist);
 
         return (nbytes);
 }
 
+/*
+ * Return how many bytes we can copy into our buffer, limited by either cols or
+ * bufsiz depending on whether AUTOWRAP is on.  Note that typically,
+ * mdb_iob_set_autowrap() will have already checked for an existing
+ * "->iob_nbytes > ->iob_cols" situation, but we double check here anyway.
+ */
+static size_t
+iob_bufleft(mdb_iob_t *iob)
+{
+        if (IOB_AUTOWRAP(iob)) {
+                if (iob->iob_cols < iob->iob_nbytes) {
+                        mdb_iob_nl(iob);
+                        ASSERT(iob->iob_cols >= iob->iob_nbytes);
+                }
+                return (iob->iob_cols - iob->iob_nbytes);
+        }
+
+        ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
+        return (iob->iob_bufsiz - iob->iob_nbytes);
+}
+
 void
 mdb_iob_nputs(mdb_iob_t *iob, const char *s, size_t nbytes)
 {
         size_t m, n, nleft = nbytes;
         const char *p, *q = s;

@@ -1808,24 +1829,15 @@
                 nleft -= (size_t)(p - q) + 1;   /* Update byte count */
                 q = p + 1;                      /* Advance past delimiter */
         }
 
         /*
-         * For a given string component, we determine how many bytes (n) we can
-         * copy into our buffer (limited by either cols or bufsiz depending
-         * on whether AUTOWRAP is on), copy a chunk into the buffer, and
+         * For a given string component, we copy a chunk into the buffer, and
          * flush the buffer if we reach the end of a line.
          */
         while (nleft != 0) {
-                if (IOB_AUTOWRAP(iob)) {
-                        ASSERT(iob->iob_cols >= iob->iob_nbytes);
-                        n = iob->iob_cols - iob->iob_nbytes;
-                } else {
-                        ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
-                        n = iob->iob_bufsiz - iob->iob_nbytes;
-                }
-
+                n = iob_bufleft(iob);
                 m = MIN(nleft, n); /* copy at most n bytes in this pass */
 
                 bcopy(q, iob->iob_bufp, m);
                 nleft -= m;
                 q += m;

@@ -1882,18 +1894,11 @@
         size_t i, m, n;
 
         ASSERT(iob->iob_flags & MDB_IOB_WRONLY);
 
         while (nfill != 0) {
-                if (IOB_AUTOWRAP(iob)) {
-                        ASSERT(iob->iob_cols >= iob->iob_nbytes);
-                        n = iob->iob_cols - iob->iob_nbytes;
-                } else {
-                        ASSERT(iob->iob_bufsiz >= iob->iob_nbytes);
-                        n = iob->iob_bufsiz - iob->iob_nbytes;
-                }
-
+                n = iob_bufleft(iob);
                 m = MIN(nfill, n); /* fill at most n bytes in this pass */
 
                 for (i = 0; i < m; i++)
                         *iob->iob_bufp++ = (char)c;
 

@@ -2166,10 +2171,30 @@
 mdb_iob_stack_size(mdb_iob_stack_t *stk)
 {
         return (stk->stk_size);
 }
 
+/*
+ * This only enables autowrap for iobs that are already autowrap themselves such
+ * as mdb.m_out typically.
+ *
+ * Note that we might be the middle of the iob buffer at this point, and
+ * specifically, iob->iob_nbytes could be more than iob->iob_cols.  As that's
+ * not a valid situation, we may need to do an autowrap *now*.
+ *
+ * In theory, we would need to do this across all MDB_IOB_AUTOWRAP iob's;
+ * instead, we have a failsafe in iob_bufleft().
+ */
+void
+mdb_iob_set_autowrap(mdb_iob_t *iob)
+{
+        mdb.m_flags |= MDB_FL_AUTOWRAP;
+        if (IOB_WRAPNOW(iob, 0))
+                mdb_iob_nl(iob);
+        ASSERT(iob->iob_cols >= iob->iob_nbytes);
+}
+
 /*
  * Stub functions for i/o backend implementors: these stubs either act as
  * pass-through no-ops or return ENOTSUP as appropriate.
  */
 ssize_t