Skip to content

[Clang] Add diagnostic about "%P" specifier with Objective-C pointers #89977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2024

Conversation

jaredgrubb
Copy link
Contributor

@jaredgrubb jaredgrubb commented Apr 24, 2024

A Darwin extension '%P' combined with an Objective-C pointer seems to always be a bug.

'%P' will dump bytes at the pointed-to address (in contrast to '%p' which dumps the pointer itself). This extension is only allowed in "OS Log" contexts and is intended to be used like %{uuid_t}.*16P or %{timeval}.*P. If an ObjC pointer is used, then the internal runtime structure (aka, the is-a pointer and other runtime metadata) will be dumped, which (IMO) is never the expectation.

A simple diagnostic can help flag these scenarios.

Resolves #89968

…pointers (llvm#89968)

A Darwin extension '%P' combined with an Objective-C pointer seems to always be a
bug.

'%P' will dump bytes at the pointed-to address (in contrast to '%p' which dumps
the pointer itself). This extension is only allowed in "OS Log" contexts and is intended
to be used like `%{uuid_t}.*16P` or `%{timeval}.*P`. If an ObjC pointer is used,
then the internal runtime structure (aka, the is-a pointer and other runtime metadata)
will be dumped, which (IMO) is never the expectation.

A simple diagnostic can help flag these scenarios.
Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be
notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write
permissions for the repository. In which case you can instead tag reviewers by
name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review
by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate
is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 24, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 24, 2024

@llvm/pr-subscribers-clang

Author: Jared Grubb (jaredgrubb)

Changes

A Darwin extension '%P' combined with an Objective-C pointer seems to always be a bug.

'%P' will dump bytes at the pointed-to address (in contrast to '%p' which dumps the pointer itself). This extension is only allowed in "OS Log" contexts and is intended to be used like %{uuid_t}.*16P or %{timeval}.*P. If an ObjC pointer is used, then the internal runtime structure (aka, the is-a pointer and other runtime metadata) will be dumped, which (IMO) is never the expectation.

A simple diagnostic can help flag these scenarios.


Full diff: https://github.com/llvm/llvm-project/pull/89977.diff

3 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+11)
  • (modified) clang/test/SemaObjC/format-strings-oslog.m (+4-1)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6732a1a98452ad..d7de9cf2c86e0e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9901,6 +9901,9 @@ def warn_format_invalid_annotation : Warning<
 def warn_format_P_no_precision : Warning<
   "using '%%P' format specifier without precision">,
   InGroup<Format>;
+def warn_format_P_with_objc_pointer : Warning<
+  "using '%%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value">,
+  InGroup<Format>;
 def warn_printf_ignored_flag: Warning<
   "flag '%0' is ignored when flag '%1' is present">,
   InGroup<Format>;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 67132701b41cfd..53dbd58b0252a2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -12544,6 +12544,17 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
     return true;
   }
 
+  // Diagnose attempts to use '%P' with ObjC object types, which will result in
+  // dumping raw class data (like is-a pointer), not actual data.
+  if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg &&
+      ExprTy->isObjCObjectPointerType()) {
+    const CharSourceRange &CSR =
+        getSpecifierRange(StartSpecifier, SpecifierLen);
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer),
+                         E->getExprLoc(), false, CSR);
+    return true;
+  }
+
   ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
   ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
   ArgType::MatchKind OrigMatch = Match;
diff --git a/clang/test/SemaObjC/format-strings-oslog.m b/clang/test/SemaObjC/format-strings-oslog.m
index 20fec93b653bd5..af5aef3d617954 100644
--- a/clang/test/SemaObjC/format-strings-oslog.m
+++ b/clang/test/SemaObjC/format-strings-oslog.m
@@ -44,15 +44,18 @@ void test_os_log_format(const char *pc, int i, void *p, void *buf) {
 }
 
 // Test os_log_format primitive with ObjC string literal format argument.
-void test_objc(const char *pc, int i, void *p, void *buf, NSString *nss) {
+void test_objc(const char *pc, int i, void *p, void *buf, NSString *nss, id obj) {
   __builtin_os_log_format(buf, @"");
   __builtin_os_log_format(buf, @"%d"); // expected-warning {{more '%' conversions than data arguments}}
   __builtin_os_log_format(buf, @"%d", i);
+
   __builtin_os_log_format(buf, @"%P", p); // expected-warning {{using '%P' format specifier without precision}}
   __builtin_os_log_format(buf, @"%.10P", p);
   __builtin_os_log_format(buf, @"%.*P", p); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}}
   __builtin_os_log_format(buf, @"%.*P", i, p);
   __builtin_os_log_format(buf, @"%.*P", i, i); // expected-warning {{format specifies type 'void *' but the argument has type 'int'}}
+  __builtin_os_log_format(buf, @"%.8P", nss);    // expected-warning {{using '%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value}}
+  __builtin_os_log_format(buf, @"%.*P", i, obj); // expected-warning {{using '%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value}}
 
   __builtin_os_log_format(buf, @"%{private}s", pc);
   __builtin_os_log_format(buf, @"%@", nss);

@jaredgrubb
Copy link
Contributor Author

Cc: @ahatanaka @egorzhdan
Also cc @joker-eph as it looks like you were original author of some of this, in case you're still following it :)

@Sirraide Sirraide requested a review from rjmccall April 24, 2024 21:40
@egorzhdan egorzhdan requested a review from ahatanak April 25, 2024 12:51
__builtin_os_log_format(buf, @"%P", p); // expected-warning {{using '%P' format specifier without precision}}
__builtin_os_log_format(buf, @"%.10P", p);
__builtin_os_log_format(buf, @"%.*P", p); // expected-warning {{field precision should have type 'int', but argument has type 'void *'}}
__builtin_os_log_format(buf, @"%.*P", i, p);
__builtin_os_log_format(buf, @"%.*P", i, i); // expected-warning {{format specifies type 'void *' but the argument has type 'int'}}
__builtin_os_log_format(buf, @"%.8P", nss); // expected-warning {{using '%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it warn when (void *)nss is passed too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, but I can be convinced. IMO, using a (void*) cast could be the escape-hatch if someone actually really does want to dump the ObjC runtime structure but also squash this warning.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that makes sense.

@egorzhdan egorzhdan changed the title [Clang] Add diagnostic about "%P" specifier with Objective-C pointers (#89968) [Clang] Add diagnostic about "%P" specifier with Objective-C pointers Apr 29, 2024
@egorzhdan egorzhdan merged commit e3750fb into llvm:main Apr 29, 2024
Copy link

@jaredgrubb Congratulations on having your first Pull Request (PR) merged into the LLVM Project!

Your changes will be combined with recent changes from other authors, then tested
by our build bots. If there is a problem with a build, you may receive a report in an email or a comment on this PR.

Please check whether problems have been caused by your change specifically, as
the builds can include changes from many authors. It is not uncommon for your
change to be included in a build that fails due to someone else's changes, or
infrastructure issues.

How to do this, and the rest of the post-merge process, is covered in detail here.

If your change does cause a problem, it may be reverted, or you can revert it yourself.
This is a normal part of LLVM development. You can fix your changes and open a new PR to merge them again.

If you don't get any reports, no action is required from you. Your changes are working as expected, well done!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category objective-c
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Clang] Add diagnostic to flag using "%P" specifier with Objective-C pointers
5 participants