elsteveogrande updated this revision to Diff 130556.
elsteveogrande marked an inline comment as done.
elsteveogrande added a comment.

Fixes, but first, a question for reviewers:

Looking at the description of `clang_disposeString`:

  /**
   * \brief Free the given string.
   */
  CINDEX_LINKAGE void clang_disposeString(CXString string);

Does it seem incorrect to acquire some `const char *` pointer into this string, 
dispose the string, and then access the characters?

I've seen this happen a couple of times now.  As I make changes to my code I 
run into this pattern.  (Since now this triggers a use-after-free abort.)

I wanted to ask because, though it seemed obvious to me that this is incorrect 
usage, I'm now wondering if the expectation is that it's ok.  Or maybe wasn't 
technically ok, and we just "got away with it" before.  :)

Anyway, assuming it's only correct to use the string before disposing it, then 
the fixes this time around are:

- Fix an ASAN use-after-free in `c-index-test` mentioned above.  Get the 
`CXString`, pass it around, then dispose when we're done with it.
- Change `createEmpty` and `createNull` to delegate through `createRef`
- `createRef` tolerates `nullptr` correctly.
- I previously ran into ASAN aborts due to mixing malloc/free/operator 
new/delete.  I had changed everything to use operator new/delete.  However from 
C-land I can't `new char[length]`, only `malloc` (or `strdup` or whatever).  
Change everything to malloc/free instead.


Repository:
  rC Clang

https://reviews.llvm.org/D42043

Files:
  .watchmanconfig
  include/clang-c/CXString.h
  tools/c-index-test/c-index-test.c
  tools/libclang/CXString.cpp
  tools/libclang/CXString.h

Index: tools/libclang/CXString.h
===================================================================
--- tools/libclang/CXString.h
+++ tools/libclang/CXString.h
@@ -106,4 +106,3 @@
 }
 
 #endif
-
Index: tools/libclang/CXString.cpp
===================================================================
--- tools/libclang/CXString.cpp
+++ tools/libclang/CXString.cpp
@@ -15,99 +15,130 @@
 
 #include "CXString.h"
 #include "CXTranslationUnit.h"
+#include "clang-c/CXString.h"
 #include "clang-c/Index.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "llvm/Support/ErrorHandling.h"
+#include <cstring>
 
-using namespace clang;
-
-/// Describes the kind of underlying data in CXString.
-enum CXStringFlag {
-  /// CXString contains a 'const char *' that it doesn't own.
-  CXS_Unmanaged,
-
-  /// CXString contains a 'const char *' that it allocated with malloc().
-  CXS_Malloc,
+static_assert(sizeof(CXString) <= 16, "");
 
-  /// CXString contains a CXStringBuf that needs to be returned to the
-  /// CXStringPool.
-  CXS_StringBuf
-};
+using namespace clang;
 
 namespace clang {
 namespace cxstring {
 
+/**
+ * This is for \b CXString 's which are created with \b CreateRef(StringRef).
+ * We'll store the info from the input \b StringRef: char ptr and size.
+ *
+ * We don't know for sure whether this is null-terminated so, when and if
+ * \b clang_getCString is called for this \b CXString, we'll allocate C string
+ * storage and copy data into the storage.  We'll memo-ize that in the
+ * \b CString member.
+ *
+ * This is refcounted; the \b Count member is initially 1.  When a \b CXString
+ * instance using this object is disposed via \b clang_disposeString, \b Count
+ * is decremented.  When this string is duplicated the \b Count increases.
+ *
+ * When \b Count finally drops to zero, the ptr at \b CString, and this object,
+ * should be deleted.
+ */
+struct RefCountedCharRange {
+  const char *Data;
+  const char *CString;
+  unsigned Size;
+  unsigned Count;
+};
+
 //===----------------------------------------------------------------------===//
 // Basic generation of CXStrings.
 //===----------------------------------------------------------------------===//
 
-CXString createEmpty() {
+CXString createRef(const char *String) {
   CXString Str;
-  Str.data = "";
-  Str.private_flags = CXS_Unmanaged;
+  Str.Contents = (const void *) String;
+  if (String) {
+    Str.Size = strlen(String);
+    Str.IsNullTerminated = true;
+  } else {
+    Str.Size = 0;
+    Str.IsNullTerminated = false;
+  }
+  Str.IsOwned = false;
+  Str.IsPooled = false;
   return Str;
 }
 
-CXString createNull() {
-  CXString Str;
-  Str.data = nullptr;
-  Str.private_flags = CXS_Unmanaged;
-  return Str;
+CXString createEmpty() {
+  return createRef("");
 }
 
-CXString createRef(const char *String) {
-  if (String && String[0] == '\0')
-    return createEmpty();
+CXString createNull() {
+  return createRef(nullptr);
+}
 
-  CXString Str;
-  Str.data = String;
-  Str.private_flags = CXS_Unmanaged;
-  return Str;
+inline static const char *copyCharRange(const char *CS, unsigned Size) {
+  char *Spelling = (char *) malloc(Size + 1);
+  assert(Spelling);
+  if (CS) {
+    memcpy(Spelling, CS, Size);
+  }
+  Spelling[Size] = 0;
+  return Spelling;
 }
 
 CXString createDup(const char *String) {
-  if (!String)
+  if (!String) {
     return createNull();
-
-  if (String[0] == '\0')
+  }
+  if (String[0] == '\0') {
     return createEmpty();
+  }
 
   CXString Str;
-  Str.data = strdup(String);
-  Str.private_flags = CXS_Malloc;
+  Str.Size = strlen(String);
+  Str.Contents = (const void *) copyCharRange(String, Str.Size);
+  Str.IsNullTerminated = true;
+  Str.IsOwned = true;
+  Str.IsPooled = false;
   return Str;
 }
 
 CXString createRef(StringRef String) {
-  // If the string is not nul-terminated, we have to make a copy.
-
-  // FIXME: This is doing a one past end read, and should be removed! For memory
-  // we don't manage, the API string can become unterminated at any time outside
-  // our control.
-
-  if (!String.empty() && String.data()[String.size()] != 0)
-    return createDup(String);
-
-  CXString Result;
-  Result.data = String.data();
-  Result.private_flags = (unsigned) CXS_Unmanaged;
-  return Result;
+  assert (String.size() <= std::numeric_limits<unsigned>::max());
+  CXString Str;
+  Str.Size = unsigned(String.size());
+  Str.IsNullTerminated = false;
+  Str.IsOwned = false;
+  Str.IsPooled = false;
+  auto *RC = new RefCountedCharRange {
+    /* Data */ String.data(),
+    /* CString */ nullptr,
+    /* Size */ Str.Size,
+    /* Count */ 1,
+  };
+  Str.Contents = (const void *) RC;
+  return Str;
 }
 
 CXString createDup(StringRef String) {
-  CXString Result;
-  char *Spelling = static_cast<char *>(malloc(String.size() + 1));
-  memmove(Spelling, String.data(), String.size());
-  Spelling[String.size()] = 0;
-  Result.data = Spelling;
-  Result.private_flags = (unsigned) CXS_Malloc;
-  return Result;
+  CXString Str;
+  Str.Size = String.size();
+  Str.Contents = (const void *) copyCharRange(String.data(), Str.Size);
+  Str.IsNullTerminated = true;
+  Str.IsOwned = true;
+  Str.IsPooled = false;
+  return Str;
 }
 
 CXString createCXString(CXStringBuf *buf) {
   CXString Str;
-  Str.data = buf;
-  Str.private_flags = (unsigned) CXS_StringBuf;
+  Str.Contents = buf->Data.data();
+  Str.Size = buf->Data.size();
+  Str.IsNullTerminated = true;
+  Str.IsOwned = false;
+  Str.IsPooled = true;
   return Str;
 }
 
@@ -151,7 +182,7 @@
 }
 
 bool isManagedByPool(CXString str) {
-  return ((CXStringFlag) str.private_flags) == CXS_StringBuf;
+  return str.IsPooled;
 }
 
 } // end namespace cxstring
@@ -161,25 +192,64 @@
 // libClang public APIs.
 //===----------------------------------------------------------------------===//
 
+using namespace clang::cxstring;
+
 const char *clang_getCString(CXString string) {
-  if (string.private_flags == (unsigned) CXS_StringBuf) {
-    return static_cast<const cxstring::CXStringBuf *>(string.data)->Data.data();
+  const char *CString = nullptr;
+
+  // If not null-terminated, then this is a reference to a range of characters
+  // owned elsewhere.  We'll need to copy this to a new C string to ensure it
+  // is null-terminated, if we haven't done so already.
+  if (string.IsNullTerminated) {
+    CString = (const char *) string.Contents;
+  } else {
+    auto *V = const_cast<void *>(string.Contents);
+    if (V) {
+      auto *R = (RefCountedCharRange *) V;
+      if (R) {
+        if (!R->CString) {
+          R->CString = copyCharRange(R->Data, R->Size);
+        }
+        CString = R->CString;
+      }
+    }
   }
-  return static_cast<const char *>(string.data);
+
+  return CString;
+}
+
+const char *clang_getStringData(CXString string) {
+  if (!(string.IsOwned || string.IsNullTerminated)) {
+    auto *R = (const RefCountedCharRange *) string.Contents;
+    return R ? R->Data : nullptr;
+  }
+  return (const char *) string.Contents;
+}
+
+unsigned clang_getStringSize(CXString string) {
+  return string.Size;
 }
 
 void clang_disposeString(CXString string) {
-  switch ((CXStringFlag) string.private_flags) {
-    case CXS_Unmanaged:
-      break;
-    case CXS_Malloc:
-      if (string.data)
-        free(const_cast<void *>(string.data));
-      break;
-    case CXS_StringBuf:
-      static_cast<cxstring::CXStringBuf *>(
-          const_cast<void *>(string.data))->dispose();
-      break;
+  if (string.IsOwned) {
+    // Is a C string that we own; need to free it.
+    const void *Chars = (const void *) string.Contents;
+    free(const_cast<void*>(Chars));
+  } else {
+    if (!string.IsNullTerminated) {
+      // Neither null-terminated nor owned.  Is a char range for which we might
+      // have created a C string.
+      auto *CR = (const RefCountedCharRange *) string.Contents;
+      auto *R = const_cast<RefCountedCharRange *>(CR);
+      if (R) {
+        -- R->Count;
+        if (!R->Count) {
+          const void *CStr = (const void *) R->CString;
+          free(const_cast<void*>(CStr));
+          delete R;
+        }
+      }
+    }
   }
 }
 
@@ -189,4 +259,3 @@
   delete[] set->Strings;
   delete set;
 }
-
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -360,6 +360,33 @@
   return CommentSchemaFile;
 }
 
+static CXString createCXString(const char *CS) {
+  CXString Str;
+
+  Str.Contents = (const void *) CS;
+  if (CS) {
+    Str.Size = strlen(CS);
+    Str.IsNullTerminated = true;
+  } else {
+    Str.Size = 0;
+    Str.IsNullTerminated = false;
+  }
+  Str.IsOwned = false;
+  Str.IsPooled = false;
+  return Str;
+}
+
+static CXString copyToCXString(const char *OrigCS) {
+  CXString Str;
+  const char *CS;
+
+  CS = strdup(OrigCS);
+  assert(CS);
+  Str = createCXString(CS);
+  Str.IsOwned = true;
+  return Str;
+}
+
 /******************************************************************************/
 /* Pretty-printing.                                                           */
 /******************************************************************************/
@@ -429,7 +456,7 @@
   if (Version.Major < 0)
     return;
   printf("%s%d", Prefix, Version.Major);
-  
+
   if (Version.Minor < 0)
     return;
   printf(".%d", Version.Minor);
@@ -740,9 +767,7 @@
   }
   assert(0 && "unknown display type"); /* no llvm_unreachable in C. */
   /* Set to NULL to prevent uninitialized variable warnings. */
-  text.data = NULL;
-  text.private_flags = 0;
-  return text;
+  return createCXString(NULL);
 }
 
 static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
@@ -787,10 +812,10 @@
           CXSourceLocation Loc;
           if (I)
             printf(", ");
-          
+
           Loc = clang_getCursorLocation(Ovl);
           clang_getSpellingLocation(Loc, 0, &line, &column, 0);
-          printf("%d:%d", line, column);          
+          printf("%d:%d", line, column);
         }
         printf("]");
       } else {
@@ -812,24 +837,24 @@
 
     if (clang_isCursorDefinition(Cursor))
       printf(" (Definition)");
-    
+
     switch (clang_getCursorAvailability(Cursor)) {
       case CXAvailability_Available:
         break;
-        
+
       case CXAvailability_Deprecated:
         printf(" (deprecated)");
         break;
-        
+
       case CXAvailability_NotAvailable:
         printf(" (unavailable)");
         break;
 
       case CXAvailability_NotAccessible:
         printf(" (inaccessible)");
         break;
     }
-    
+
     NumPlatformAvailability
       = clang_getCursorPlatformAvailability(Cursor,
                                             &AlwaysDeprecated,
@@ -847,7 +872,7 @@
       for (I = 0; I != NumPlatformAvailability; ++I) {
         if (I >= 2)
           break;
-        
+
         printf("  (%s", clang_getCString(PlatformAvailability[I].Platform));
         if (PlatformAvailability[I].Unavailable)
           printf(", unavailable");
@@ -867,7 +892,7 @@
         break;
       clang_disposeCXPlatformAvailability(PlatformAvailability + I);
     }
-    
+
     clang_disposeString(DeprecatedMessage);
     clang_disposeString(UnavailableMessage);
 
@@ -954,7 +979,7 @@
       printf(" [IBOutletCollection=%s]", clang_getCString(S));
       clang_disposeString(S);
     }
-    
+
     if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
       enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
       unsigned isVirtual = clang_isVirtualBase(Cursor);
@@ -969,8 +994,8 @@
           accessStr = "protected"; break;
         case CX_CXXPrivate:
           accessStr = "private"; break;
-      }      
-      
+      }
+
       printf(" [access=%s isVirtual=%s]", accessStr,
              isVirtual ? "true" : "false");
     }
@@ -1016,7 +1041,7 @@
     }
 
     clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
-    if (num_overridden) {      
+    if (num_overridden) {
       unsigned I;
       LineCol lineCols[50];
       assert(num_overridden <= 50);
@@ -1037,28 +1062,28 @@
       printf("]");
       clang_disposeOverriddenCursors(overridden);
     }
-    
+
     if (Cursor.kind == CXCursor_InclusionDirective) {
       CXFile File = clang_getIncludedFile(Cursor);
       CXString Included = clang_getFileName(File);
       printf(" (%s)", clang_getCString(Included));
       clang_disposeString(Included);
-      
+
       if (clang_isFileMultipleIncludeGuarded(TU, File))
         printf("  [multi-include guarded]");
     }
-    
+
     CursorExtent = clang_getCursorExtent(Cursor);
-    RefNameRange = clang_getCursorReferenceNameRange(Cursor, 
+    RefNameRange = clang_getCursorReferenceNameRange(Cursor,
                                                    CXNameRange_WantQualifier
                                                  | CXNameRange_WantSinglePiece
                                                  | CXNameRange_WantTemplateArgs,
                                                      0);
     if (!clang_equalRanges(CursorExtent, RefNameRange))
       PrintRange(RefNameRange, "SingleRefName");
-    
+
     for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
-      RefNameRange = clang_getCursorReferenceNameRange(Cursor, 
+      RefNameRange = clang_getCursorReferenceNameRange(Cursor,
                                                    CXNameRange_WantQualifier
                                                  | CXNameRange_WantTemplateArgs,
                                                        RefNameRangeNr);
@@ -1111,28 +1136,24 @@
   }
 }
 
-static const char* GetCursorSource(CXCursor Cursor) {
+static CXString GetCursorSource(CXCursor Cursor) {
   CXSourceLocation Loc = clang_getCursorLocation(Cursor);
   CXString source;
   CXFile file;
+  const char *sourceCStr;
+  CXString result;
+
   clang_getExpansionLocation(Loc, &file, 0, 0, 0);
   source = clang_getFileName(file);
-  if (!clang_getCString(source)) {
-    clang_disposeString(source);
-    return "<invalid loc>";
-  }
-  else {
-    const char *b = basename(clang_getCString(source));
-    clang_disposeString(source);
-    return b;
+  sourceCStr = clang_getCString(source);
+  if (!sourceCStr) {
+    result = createCXString("<invalid loc>");
+  } else {
+    result = copyToCXString(basename(sourceCStr));
   }
-}
 
-static CXString createCXString(const char *CS) {
-  CXString Str;
-  Str.data = (const void *) CS;
-  Str.private_flags = 0;
-  return Str;
+  clang_disposeString(source);
+  return result;
 }
 
 /******************************************************************************/
@@ -1206,7 +1227,7 @@
     PrintDiagnostic(Diag);
     if (ChildDiags)
       PrintDiagnosticSet(ChildDiags);
-  }  
+  }
 }
 
 void PrintDiagnostics(CXTranslationUnit TU) {
@@ -1229,7 +1250,7 @@
   }
   fprintf(stderr, "  TOTAL = %ld bytes (%f MBytes)\n", total,
           ((double) total)/(1024*1024));
-  clang_disposeCXTUResourceUsage(usage);  
+  clang_disposeCXTUResourceUsage(usage);
 }
 
 /******************************************************************************/
@@ -1252,13 +1273,17 @@
 enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
                                                 CXCursor Parent,
                                                 CXClientData ClientData) {
+  CXString Source;
+  const char *SourceCStr;
   VisitorData *Data = (VisitorData *)ClientData;
   if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
     CXSourceLocation Loc = clang_getCursorLocation(Cursor);
     unsigned line, column;
     clang_getSpellingLocation(Loc, 0, &line, &column, 0);
-    printf("// %s: %s:%d:%d: ", FileCheckPrefix,
-           GetCursorSource(Cursor), line, column);
+    Source = GetCursorSource(Cursor);
+    SourceCStr = clang_getCString(Source);
+    printf("// %s: %s:%d:%d: ", FileCheckPrefix, SourceCStr, line, column);
+    clang_disposeString(Source);
     PrintCursor(Cursor, Data->CommentSchemaFile);
     PrintCursorExtent(Cursor);
     if (clang_isDeclaration(Cursor.kind)) {
@@ -1308,6 +1333,8 @@
     CXSourceLocation Loc;
     CXFile file;
     CXString source;
+    CXString curSource;
+    const char *curSourceCStr;
 
     if (*startBuf == '\n') {
       startBuf++;
@@ -1327,8 +1354,11 @@
       if (Ref.kind == CXCursor_NoDeclFound) {
         /* Nothing found here; that's fine. */
       } else if (Ref.kind != CXCursor_FunctionDecl) {
-        printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
+        curSource = GetCursorSource(Ref);
+        curSourceCStr = clang_getCString(curSource);
+        printf("// %s: %s:%d:%d: ", FileCheckPrefix, curSourceCStr,
                curLine, curColumn);
+        clang_disposeString(curSource);
         PrintCursor(Ref, Data->CommentSchemaFile);
         printf("\n");
       }
@@ -1346,15 +1376,21 @@
 
 enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
                                    CXClientData ClientData) {
+  CXString Source;
+  const char *SourceCStr;
   VisitorData *Data = (VisitorData *)ClientData;
+
   if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
     CXString USR = clang_getCursorUSR(C);
     const char *cstr = clang_getCString(USR);
     if (!cstr || cstr[0] == '\0') {
       clang_disposeString(USR);
       return CXChildVisit_Recurse;
     }
-    printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
+    Source = GetCursorSource(C);
+    SourceCStr = clang_getCString(Source);
+    printf("// %s: %s %s", FileCheckPrefix, SourceCStr, cstr);
+    clang_disposeString(Source);
 
     PrintCursorExtent(C);
     printf("\n");
@@ -1778,7 +1814,7 @@
 
     /* Perform some simple filtering. */
     if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
-    else if (!strcmp(filter, "all-display") || 
+    else if (!strcmp(filter, "all-display") ||
              !strcmp(filter, "local-display")) {
       ck = NULL;
       wanted_display_type = DisplayType_DisplayName;
@@ -1928,11 +1964,11 @@
   int trial;
   int remap_after_trial = 0;
   char *endptr = 0;
-  
+
   Idx = clang_createIndex(/* excludeDeclsFromPCH */
                           !strcmp(filter, "local") ? 1 : 0,
                           /* displayDiagnostics=*/1);
-  
+
   if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
     clang_disposeIndex(Idx);
     return -1;
@@ -1946,7 +1982,7 @@
     compiler_arg_idx = i+1;
   if (num_unsaved_files > compiler_arg_idx)
     compiler_arg_idx = num_unsaved_files;
-  
+
   /* Load the initial translation unit -- we do this without honoring remapped
    * files, so that we have a way to test results after changing the source. */
   Err = clang_parseTranslationUnit2(Idx, 0,
@@ -1960,7 +1996,7 @@
     clang_disposeIndex(Idx);
     return 1;
   }
-  
+
   if (checkForErrors(TU) != 0)
     return -1;
 
@@ -1989,13 +2025,13 @@
       clang_disposeTranslationUnit(TU);
       free_remapped_files(unsaved_files, num_unsaved_files);
       clang_disposeIndex(Idx);
-      return -1;      
+      return -1;
     }
 
     if (checkForErrors(TU) != 0)
       return -1;
   }
-  
+
   result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
 
   free_remapped_files(unsaved_files, num_unsaved_files);
@@ -2246,7 +2282,7 @@
                               file);
       fprintf(file, "}");
       continue;
-    } 
+    }
 
     if (Kind == CXCompletionChunk_VerticalSpace) {
       fprintf(file, "{VerticalSpace  }");
@@ -2272,21 +2308,21 @@
   CXString BriefComment;
   CXString Annotation;
   const char *BriefCommentCString;
-  
+
   fprintf(file, "%s:", clang_getCString(ks));
   clang_disposeString(ks);
 
   print_completion_string(completion_result->CompletionString, file);
-  fprintf(file, " (%u)", 
+  fprintf(file, " (%u)",
           clang_getCompletionPriority(completion_result->CompletionString));
   switch (clang_getCompletionAvailability(completion_result->CompletionString)){
   case CXAvailability_Available:
     break;
-    
+
   case CXAvailability_Deprecated:
     fprintf(file, " (deprecated)");
     break;
-    
+
   case CXAvailability_NotAvailable:
     fprintf(file, " (unavailable)");
     break;
@@ -2332,7 +2368,7 @@
     fprintf(file, "(brief comment: %s)", BriefCommentCString);
   }
   clang_disposeString(BriefComment);
-  
+
   fprintf(file, "\n");
 }
 
@@ -2431,7 +2467,7 @@
     completionOptions |= CXCodeComplete_IncludeBriefComments;
   if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
     completionOptions |= CXCodeComplete_SkipPreamble;
-  
+
   if (timing_only)
     input += strlen("-code-completion-timing=");
   else
@@ -2490,7 +2526,7 @@
     enum CXCursorKind containerKind;
     CXString objCSelector;
     const char *selectorString;
-    if (!timing_only) {      
+    if (!timing_only) {
       /* Sort the code-completion results based on the typed text. */
       clang_sortCodeCompletionResults(results->Results, results->NumResults);
 
@@ -2503,39 +2539,39 @@
       PrintDiagnostic(diag);
       clang_disposeDiagnostic(diag);
     }
-    
+
     contexts = clang_codeCompleteGetContexts(results);
     print_completion_contexts(contexts, stdout);
-    
+
     containerKind = clang_codeCompleteGetContainerKind(results,
                                                        &containerIsIncomplete);
-    
+
     if (containerKind != CXCursor_InvalidCode) {
       /* We have found a container */
       CXString containerUSR, containerKindSpelling;
       containerKindSpelling = clang_getCursorKindSpelling(containerKind);
       printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
       clang_disposeString(containerKindSpelling);
-      
+
       if (containerIsIncomplete) {
         printf("Container is incomplete\n");
       }
       else {
         printf("Container is complete\n");
       }
-      
+
       containerUSR = clang_codeCompleteGetContainerUSR(results);
       printf("Container USR: %s\n", clang_getCString(containerUSR));
       clang_disposeString(containerUSR);
     }
-    
+
     objCSelector = clang_codeCompleteGetObjCSelector(results);
     selectorString = clang_getCString(objCSelector);
     if (selectorString && strlen(selectorString) > 0) {
       printf("Objective-C selector: %s\n", selectorString);
     }
     clang_disposeString(objCSelector);
-    
+
     clang_disposeCodeCompleteResults(results);
   }
   clang_disposeTranslationUnit(TU);
@@ -2569,7 +2605,7 @@
   unsigned NumLocations = 0, Loc;
   unsigned Repeats = 1;
   unsigned I;
-  
+
   /* Count the number of locations. */
   while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
     ++NumLocations;
@@ -2624,7 +2660,7 @@
 
     if (checkForErrors(TU) != 0)
       return -1;
-    
+
     for (Loc = 0; Loc < NumLocations; ++Loc) {
       CXFile file = clang_getFile(TU, Locations[Loc].filename);
       if (!file)
@@ -2643,7 +2679,7 @@
       }
     }
   }
-  
+
   PrintDiagnostics(TU);
   clang_disposeTranslationUnit(TU);
   clang_disposeIndex(CIdx);
@@ -2862,7 +2898,7 @@
   unsigned NumLocations = 0, Loc;
   unsigned Repeats = 1;
   unsigned I;
-  
+
   /* Count the number of locations. */
   while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
     ++NumLocations;
@@ -2918,7 +2954,7 @@
 
     if (checkForErrors(TU) != 0)
       return -1;
-    
+
     for (Loc = 0; Loc < NumLocations; ++Loc) {
       CXFile file = clang_getFile(TU, Locations[Loc].filename);
       if (!file)
@@ -2943,7 +2979,7 @@
       }
     }
   }
-  
+
   PrintDiagnostics(TU);
   clang_disposeTranslationUnit(TU);
   clang_disposeIndex(CIdx);
@@ -3138,7 +3174,7 @@
   unsigned line, column;
   const char *main_filename;
   int isMainFile;
-  
+
   index_data = (IndexData *)client_data;
   clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
   if (line == 0) {
@@ -3184,7 +3220,7 @@
   char *newStr;
   CXIdxClientFile file;
   unsigned line, column;
-  
+
   name = info->name;
   if (!name)
     name = "<anon-tag>";
@@ -3342,8 +3378,8 @@
     str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
     cstr = clang_getCString(str);
     printf("[diagnostic]: %s\n", cstr);
-    clang_disposeString(str);  
-  
+    clang_disposeString(str);
+
     if (getenv("CINDEXTEST_FAILONERROR") &&
         clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
       index_data->fail_for_error = 1;
@@ -3381,7 +3417,7 @@
   printCXIndexLoc(info->hashLoc, client_data);
   printf(" | isImport: %d | isAngled: %d | isModule: %d",
          info->isImport, info->isAngled, info->isModuleImport);
-  
+
   Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
   if (Mod) {
     CXString str = clang_Module_getFullName(Mod);
@@ -3406,7 +3442,7 @@
     importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
     clang_disposeString(filename);
   }
-  
+
   printf("[importedASTFile]: ");
   printCXIndexFile((CXIdxClientFile)info->file);
   if (info->module) {
@@ -4269,9 +4305,9 @@
   int num_unsaved_files = 0;
   enum CXErrorCode Err;
   int result = 0;
-  
+
   Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
-  
+
   if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
     clang_disposeIndex(Idx);
     return -1;
@@ -4293,30 +4329,30 @@
     return 1;
   }
 
-  switch (clang_saveTranslationUnit(TU, filename, 
+  switch (clang_saveTranslationUnit(TU, filename,
                                     clang_defaultSaveOptions(TU))) {
   case CXSaveError_None:
     break;
 
   case CXSaveError_TranslationErrors:
-    fprintf(stderr, "Unable to write PCH file %s: translation errors\n", 
+    fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
             filename);
-    result = 2;    
+    result = 2;
     break;
 
   case CXSaveError_InvalidTU:
-    fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n", 
+    fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
             filename);
-    result = 3;    
+    result = 3;
     break;
 
   case CXSaveError_Unknown:
   default:
     fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
     result = 1;
     break;
   }
-  
+
   clang_disposeTranslationUnit(TU);
   free_remapped_files(unsaved_files, num_unsaved_files);
   clang_disposeIndex(Idx);
@@ -4363,23 +4399,23 @@
   CXFile File;
   CXString FileName;
   unsigned line, column, offset;
-  
+
   clang_getExpansionLocation(L, &File, &line, &column, &offset);
   FileName = clang_getFileName(File);
-  
+
   fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
   clang_disposeString(FileName);
 }
 
 static void printRanges(CXDiagnostic D, unsigned indent) {
   unsigned i, n = clang_getDiagnosticNumRanges(D);
-  
+
   for (i = 0; i < n; ++i) {
     CXSourceLocation Start, End;
     CXSourceRange SR = clang_getDiagnosticRange(D, i);
     Start = clang_getRangeStart(SR);
     End = clang_getRangeEnd(SR);
-    
+
     printIndent(indent);
     fprintf(stderr, "Range: ");
     printLocation(Start);
@@ -4396,40 +4432,40 @@
     CXSourceRange ReplacementRange;
     CXString text;
     text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
-    
+
     printIndent(indent);
     fprintf(stderr, "FIXIT: (");
     printLocation(clang_getRangeStart(ReplacementRange));
     fprintf(stderr, " - ");
     printLocation(clang_getRangeEnd(ReplacementRange));
     fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
     clang_disposeString(text);
-  }  
+  }
 }
 
 static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
   unsigned i, n;
 
   if (!Diags)
     return;
-  
+
   n = clang_getNumDiagnosticsInSet(Diags);
   for (i = 0; i < n; ++i) {
     CXSourceLocation DiagLoc;
     CXDiagnostic D;
     CXFile File;
     CXString FileName, DiagSpelling, DiagOption, DiagCat;
     unsigned line, column, offset;
     const char *DiagOptionStr = 0, *DiagCatStr = 0;
-    
+
     D = clang_getDiagnosticInSet(Diags, i);
     DiagLoc = clang_getDiagnosticLocation(D);
     clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
     FileName = clang_getFileName(File);
     DiagSpelling = clang_getDiagnosticSpelling(D);
-    
+
     printIndent(indent);
-    
+
     fprintf(stderr, "%s:%d:%d: %s: %s",
             clang_getCString(FileName),
             line,
@@ -4442,42 +4478,42 @@
     if (DiagOptionStr) {
       fprintf(stderr, " [%s]", DiagOptionStr);
     }
-    
+
     DiagCat = clang_getDiagnosticCategoryText(D);
     DiagCatStr = clang_getCString(DiagCat);
     if (DiagCatStr) {
       fprintf(stderr, " [%s]", DiagCatStr);
     }
-    
+
     fprintf(stderr, "\n");
-    
+
     printRanges(D, indent);
     printFixIts(D, indent);
-    
+
     /* Print subdiagnostics. */
     printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
 
     clang_disposeString(FileName);
     clang_disposeString(DiagSpelling);
     clang_disposeString(DiagOption);
     clang_disposeString(DiagCat);
-  }  
+  }
 }
 
 static int read_diagnostics(const char *filename) {
   enum CXLoadDiag_Error error;
   CXString errorString;
   CXDiagnosticSet Diags = 0;
-  
+
   Diags = clang_loadDiagnostics(filename, &error, &errorString);
   if (!Diags) {
     fprintf(stderr, "Trouble deserializing file (%s): %s\n",
             getDiagnosticCodeStr(error),
             clang_getCString(errorString));
     clang_disposeString(errorString);
     return 1;
   }
-  
+
   printDiagnosticSet(Diags, 0);
   fprintf(stderr, "Number of diagnostics: %d\n",
           clang_getNumDiagnosticsInSet(Diags));
@@ -4606,17 +4642,17 @@
     CXCursorVisitor I = GetVisitor(argv[1] + 25);
     if (I) {
       int trials = atoi(argv[2]);
-      return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I, 
+      return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
                                          NULL);
     }
   }
   else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
     CXCursorVisitor I = GetVisitor(argv[1] + 17);
-    
+
     PostVisitTU postVisit = 0;
     if (strstr(argv[1], "-memory-usage"))
       postVisit = PrintMemoryUsage;
-    
+
     if (I)
       return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
                                       postVisit);
Index: include/clang-c/CXString.h
===================================================================
--- include/clang-c/CXString.h
+++ include/clang-c/CXString.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_C_CXSTRING_H
 
 #include "clang-c/Platform.h"
+#include <stdbool.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -36,8 +37,11 @@
  * with the string data, call \c clang_disposeString() to free the string.
  */
 typedef struct {
-  const void *data;
-  unsigned private_flags;
+  const void *Contents;
+  unsigned Size;
+  bool IsNullTerminated;
+  bool IsOwned;
+  bool IsPooled;
 } CXString;
 
 typedef struct {
@@ -47,10 +51,33 @@
 
 /**
  * \brief Retrieve the character data associated with the given string.
+ *
+ * This returns a pointer to a C string even if this \b CXString was built
+ * from e.g. a StringRef reference (which is not null-terminated).  In those
+ * cases a string copy is performed on-demand.
+ *
+ * See also \b clang_getStringData and \b clang_getStringSize which could
+ * provide a range or "window" of data, if needed, and a C string is not
+ * strictly needed; this could save a C string allocation, deallocation, and
+ * string copy.
  */
 CINDEX_LINKAGE const char *clang_getCString(CXString string);
 
 /**
+ * \brief Retrieve a pointer to the start of the character data for this string.
+ *
+ * Note that the string is not necessarily null-terminated, so it might not be
+ * suitable for use as a C string.  See \b clang_getCString which guarantees
+ * a C string result.
+ */
+CINDEX_LINKAGE const char *clang_getStringData(CXString string);
+
+/**
+ * \brief Retrieve the string length (not including null-terminator, if any).
+ */
+CINDEX_LINKAGE unsigned clang_getStringSize(CXString string);
+
+/**
  * \brief Free the given string.
  */
 CINDEX_LINKAGE void clang_disposeString(CXString string);
@@ -68,4 +95,3 @@
 }
 #endif
 #endif
-
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to