bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH mig] Add support for dynamically sized strings


From: Flavio Cruz
Subject: [PATCH mig] Add support for dynamically sized strings
Date: Thu, 27 Apr 2023 23:00:37 -0400

Dynamically sized strings can be represented as c_string[*] (*). We inline
up to 64 bytes but can pass arbitrary strings if needed out of line. Currently
implementation is limited to input arguments only (MiG will error out if
used as output).

In the user stub, we first run strlen on the parameter to get
its length and pass it to msgtl_number. If the size is greater than 64,
then we pass the pointer instead, otherwise we strncpy the parameter
into the message and limit the size of the string in the final message
to only mach_msg_type_long_t + strlen(string) + 1.

Tested by replacing file name for dir_lookup using c_string[*] and
bootstrapping the whole system.

(*) Today we have two other ways to use c_string:
- c_string[N]: uses a fixed size for the string and messages
always include that size if the string is smaller.
- c_string[*: N]: identical to the above as the string is limited to
length N, however, the size of the string that it occupies in the final
message is always mach_msg_type_t + strlen(string) + 1. Interestingly,
if strlen == N then the string will not be null-terminated.
---
 parser.y               |  2 ++
 routine.c              |  3 +++
 tests/good/Makefile.am |  2 +-
 tests/good/string.defs | 36 +++++++++++++++++++++++++
 tests/includes/types.h |  5 ++++
 tests/test_lib.sh      |  2 +-
 type.c                 | 48 ++++++++++++++++++++++++++++-----
 type.h                 | 10 +++----
 user.c                 | 61 ++++++++++++++++++++++++++++++------------
 9 files changed, 139 insertions(+), 30 deletions(-)
 create mode 100644 tests/good/string.defs

diff --git a/parser.y b/parser.y
index ccf4726..eb7bb1a 100644
--- a/parser.y
+++ b/parser.y
@@ -609,6 +609,8 @@ CStringSpec         :       syCString syLBrack IntExp 
syRBrack
                        |       syCString syLBrack syStar syColon
                                IntExp syRBrack
                                { $$ = itCStringDecl($5, true); }
+                       |       syCString syLBrack syStar syRBrack
+                               { $$ = itIndefiniteCStringDecl(); }
                        ;
 
 IntExp                 :       IntExp  syPlus  IntExp
diff --git a/routine.c b/routine.c
index 3ae9298..d5edb67 100644
--- a/routine.c
+++ b/routine.c
@@ -865,6 +865,9 @@ rtCheckRoutineArgs(routine_t *rt)
            if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ||
                (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
                rtAddPolyArg(arg);
+           if (it->itString && it->itIndefinite &&
+               akCheck(arg->argKind, akbReply))
+               error("%s: c_string[*] cannot be used as output arguments", 
arg->argName);
        }
     }
 }
diff --git a/tests/good/Makefile.am b/tests/good/Makefile.am
index c5d8d7e..53a342d 100644
--- a/tests/good/Makefile.am
+++ b/tests/good/Makefile.am
@@ -17,7 +17,7 @@
 #
 
 TESTS = case.defs complex-types.defs directions.defs import.defs \
-        routine.defs types.defs waittime.defs
+        routine.defs string.defs types.defs waittime.defs
 EXTRA_DIST = $(TESTS) run_good_test.sh
 DEFS_LOG_COMPILER = sh ./$(srcdir)/run_good_test.sh
 
diff --git a/tests/good/string.defs b/tests/good/string.defs
new file mode 100644
index 0000000..4fa9654
--- /dev/null
+++ b/tests/good/string.defs
@@ -0,0 +1,36 @@
+/*
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file is part of GNU MIG.
+
+   GNU MIG is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   GNU MIG is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU MIG.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Tests the different string types.  */
+subsystem string 500;
+
+import "types.h";
+import "string.h";
+
+type fixed_string = c_string[16];
+type mach_port_t = MACH_MSG_TYPE_COPY_SEND;
+type variable_string = c_string[*: 16]
+   ctype: fixed_string;
+type dynamic_string = c_string[*];
+
+routine call(port : mach_port_t; fixed : fixed_string;
+             var: variable_string;
+             ind: dynamic_string;
+             ind2: dynamic_string;
+             out fixedret : fixed_string;
+             out varret: variable_string);
diff --git a/tests/includes/types.h b/tests/includes/types.h
index 2a70443..50d43c4 100644
--- a/tests/includes/types.h
+++ b/tests/includes/types.h
@@ -59,4 +59,9 @@ static inline int int8_to_int(int8_t n) {
   return (int) n;
 }
 
+typedef char fixed_string[16];
+typedef const char const_fixed_string[16];
+typedef char * dynamic_string;
+typedef const char * const_dynamic_string;
+
 #endif
diff --git a/tests/test_lib.sh b/tests/test_lib.sh
index 60241d9..b2679ba 100644
--- a/tests/test_lib.sh
+++ b/tests/test_lib.sh
@@ -32,7 +32,7 @@ run_mig () {
   file="$1"
   module="$2"
   echo "Generating stubs for $module..."
-  cpp $file -I$TEST_DIR | $MIGCOM -server $module-server.c -user 
$module-user.c -header $module-header.h
+  cpp $file -I$TEST_DIR | $MIGCOM -v -server $module-server.c -user 
$module-user.c -header $module-header.h
 }
 
 test_module () {
diff --git a/type.c b/type.c
index 15843e3..6158c14 100644
--- a/type.c
+++ b/type.c
@@ -458,7 +458,14 @@ itPrintDecl(identifier_t name, const ipc_type_t *it)
     printf("Type %s = ", name);
     if (!it->itInLine)
        printf("^ ");
-    if (it->itVarArray)
+    if (it->itString)
+       if (it->itNumber == 0 || it->itIndefinite)
+        printf("c_string[*]");
+        else if (it->itNumber > 0 && !it->itVarArray)
+            printf("c_string[%d]", it->itNumber);
+        else
+           printf("c_string[*:%d]", it->itNumber);
+    else if (it->itVarArray)
        if (it->itNumber == 0 || it->itIndefinite)
            printf("array [] of ");
        else
@@ -469,12 +476,16 @@ itPrintDecl(identifier_t name, const ipc_type_t *it)
     else if (it->itNumber != 1)
        printf("array [%d] of ", it->itNumber);
 
-    if (streql(it->itInNameStr, it->itOutNameStr))
-       printf("(%s,", it->itInNameStr);
-    else
-       printf("(%s|%s", it->itInNameStr, it->itOutNameStr);
+    if (it->itString) {
+        printf("(");
+    } else {
+           if (streql(it->itInNameStr, it->itOutNameStr))
+               printf("(%s, ", it->itInNameStr);
+           else
+               printf("(%s|%s ", it->itInNameStr, it->itOutNameStr);
+    }
 
-    printf(" %d%s%s)\n", it->itSize,   it->itLongForm ? ", IsLong" : "",
+    printf("%d%s%s)\n", it->itSize,    it->itLongForm ? ", IsLong" : "",
           it->itDeallocate == d_YES ? ", Dealloc"
                                     :it->itDeallocate == d_MAYBE ?", Dealloc[]"
                                                                  : "");
@@ -770,6 +781,31 @@ itCStringDecl(u_int count, bool varying)
     return it;
 }
 
+ipc_type_t*
+itIndefiniteCStringDecl(void) {
+    ipc_type_t *it;
+    ipc_type_t *itElement;
+
+    itElement = itShortDecl(MACH_MSG_TYPE_STRING_C,
+                           "MACH_MSG_TYPE_STRING_C",
+                           MACH_MSG_TYPE_STRING_C,
+                           "MACH_MSG_TYPE_STRING_C",
+                           8);
+    itCheckDecl("char", itElement);
+
+    it = itResetType(itCopyType(itElement));
+    it->itVarArray = true;
+    it->itStruct = false;
+    it->itString = true;
+    /* We will inline this many bytes before sending out of line */
+    it->itNumber = 64;
+    it->itIndefinite = true;
+    it->itAlignment = itElement->itAlignment;
+
+    itCalculateSizeInfo(it);
+    return it;
+}
+
 /* Creates a new MIG type based on a basic integral C type. */
 static ipc_type_t *
 itCIntTypeDecl(const_string_t ctype, const size_t size)
diff --git a/type.h b/type.h
index 1e4e49f..1ac2ff0 100644
--- a/type.h
+++ b/type.h
@@ -116,16 +116,15 @@ typedef enum dealloc {
  * by reference).  If itStruct is true, then msg data is passed by value
  * and can be assigned with =.  If itString is true, then the msg_data
  * is a null-terminated string, assigned with strncpy.  The itNumber
- * value is a maximum length for the string; the msg field always
- * takes up this much space.
+ * value is a maximum length for the string to be sent inline.
  *
  * itVarArray means this is a variable-sized array.  If it is inline,
  * then itStruct and itString are false.  If it is out-of-line, then
  * itStruct is true (because pointers can be assigned).
  *
- * itIndefinite means this is an indefinite-length array - it may be sent
- * either inline or out-of-line.  itNumber is assigned so that at most
- * 2048 bytes are sent inline.
+ * itIndefinite means this is an indefinite-length array or string -
+ * it may be sent either inline or out-of-line.  itNumber is assigned
+ * so that at most 2048 or 64 bytes, for arrays or strings, respectively.
  *
  * itElement points to any substructure that the type may have.
  * It is only used with variable-sized array types.
@@ -197,6 +196,7 @@ extern ipc_type_t *itPtrDecl(ipc_type_t *it);
 extern ipc_type_t *itStructArrayDecl(u_int number, const ipc_type_t *it);
 extern ipc_type_t *itStructDecl(u_int min_type_size_in_bytes, u_int 
required_alignment_in_bytes);
 extern ipc_type_t *itCStringDecl(u_int number, bool varying);
+extern ipc_type_t *itIndefiniteCStringDecl(void);
 
 extern ipc_type_t *itRetCodeType;
 extern ipc_type_t *itDummyType;
diff --git a/user.c b/user.c
index dc9e21f..ce61428 100644
--- a/user.c
+++ b/user.c
@@ -396,23 +396,48 @@ WritePackArgValue(FILE *file, const argument_t *arg)
     if (it->itInLine && it->itVarArray) {
 
        if (it->itString) {
-           /*
-            *  Copy variable-size C string with mig_strncpy.
-            *  Save the string length (+ 1 for trailing 0)
-            *  in the argument`s count field.
-            */
-           fprintf(file,
-               "\tInP->%s = %smig_strncpy(InP->%s, %s, %d);\n",
-               arg->argCount->argMsgField,
-               SubrPrefix,
-               arg->argMsgField,
-               arg->argVarName,
-               it->itNumber);
-           fprintf(file,
-               "\tif (InP->%s < %d) InP->%s += 1;\n",
-               arg->argCount->argMsgField,
-               it->itNumber,
-               arg->argCount->argMsgField);
+           if (it->itIndefinite) {
+               fprintf(file, "\tInP->%s = strlen(%s) + 1;\n",
+                               arg->argCount->argMsgField, arg->argVarName);
+               fprintf(file, "\tif (InP->%s > %d) {\n",
+                               arg->argCount->argMsgField,
+                               it->itNumber);
+               fprintf(file, "\t\tInP->%s%s.msgt_inline = FALSE;\n",
+                       arg->argTTName,
+                       arg->argLongForm ? ".msgtl_header" : "");
+               fprintf(file, "\t\tInP->%s%s = %s%s;\n",
+                       arg->argMsgField,
+                       OOLPostfix,
+                       ref, arg->argVarName);
+               if (!arg->argRoutine->rtSimpleFixedRequest)
+                   fprintf(file, "\t\tmsgh_simple = FALSE;\n");
+               fprintf(file, "\t} else {\n");
+               fprintf(file,
+                   "\t\t(void) %smig_strncpy(InP->%s, %s, %d);\n",
+                   SubrPrefix,
+                   arg->argMsgField,
+                   arg->argVarName,
+                   it->itNumber);
+               fprintf(file, "\t}\n");
+           } else {
+               /*
+                *      Copy variable-size C string with mig_strncpy.
+                *      Save the string length (+ 1 for trailing 0)
+                *      in the argument`s count field.
+                */
+               fprintf(file,
+                   "\tInP->%s = %smig_strncpy(InP->%s, %s, %d);\n",
+                   arg->argCount->argMsgField,
+                   SubrPrefix,
+                   arg->argMsgField,
+                   arg->argVarName,
+                   it->itNumber);
+               fprintf(file,
+                   "\tif (InP->%s < %d) InP->%s += 1;\n",
+                   arg->argCount->argMsgField,
+                   it->itNumber,
+                   arg->argCount->argMsgField);
+           }
        }
        else {
 
@@ -921,6 +946,8 @@ WriteExtractArgValue(FILE *file, const argument_t *arg)
     if (argType->itInLine && argType->itVarArray) {
 
        if (argType->itString) {
+           /* Indefinite strings are not supported as output.  */
+           assert(!argType->itIndefinite);
            /*
             *  Copy out variable-size C string with mig_strncpy.
             */
-- 
2.39.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]