[cfe-dev] type specifiers in scanf/sscanf and NSInteger

Александр Шапошников via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 8 19:05:38 PDT 2017


Hi,
recently, i was looking into Clang's fixits generated for the format string
used in
"printf" / "scanf" for some common ObjC types.
There is some relevant public documentation here:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html
.
It turns out that in the case of "scanf" there are some extra complications
and
I would like to ask for your advice.

So let's take a look at the following two examples:

(Example 1)

   void printNSInteger() {
       NSInteger x = 123;
       printf("%d", x);
   }
A. If the triple is 32-bit this code compiles cleanly with -Wformat -fixit
B. If the triple is 64-bit Clang will generate a warning and the
corresponding fixit
replaces printf("%d", x) with printf("%ld", (long)x).
The new code has an important property that it's correct for 32-bit targets
as well.

(Example 2)

  void readNSInteger() {
     NSInteger x;
     scanf("%d", &x);
  }

A. If the triple is 32-bit this code compiles cleanly with -Wformat -fixit
B. If the triple is 64-bit Clang will generate a warning and the
corresponding fixit
which replaces scanf("%d", &x); with scanf("%ld", &x);
Unfortunately, the new code is broken for 32-bits targets:

Simple test:
#include <stdio.h>
typedef struct {
  int x;
  int y;
} Point;
int main() {
  Point p = { 1, 1 };
  scanf("%ld", &p.x);
  printf("%d %d\n", p.x, p.y);
  return 0;
}
./main <<< '2'
will print 2 0 (so p.y was overwritten by scanf).

This becomes an issue for some shared code which is compiled for 32-bit and
64 bit targets.
A natural question comes up what the proper "fixit" for readNSInteger()
should look like
and how it would coexist with the current warnings/fixits. I will list a
few options (mostly to start a discussion) which come on my mind first, but
i am interested in your opinion, plus
i assume i might be missing something.

Option 1:
Make "fixit" produce the following code modification
(if the code is compiled for 64 bits target):

replace (that's just a sketch, because there are some complications with
function-style macros and macro parameters)

scanf("%d", &x);

with

#if defined (_LP64_)
scanf("%ld", &x);
#else
scanf("%d", &x);
#endif

Option 2:
"Hacky"  (inspired by
https://twitter.com/gparker/status/377910611453046784?lang=en )
Make "fixit" produce the following code modification
(if the code is compiled for 64 bits target):

replace

scanf("%d", &x);

with
scanf("%zd", &x); // aka size_t

-------------------

Kind regards,
Alexander Shaposhnikov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20170608/f13d3f8d/attachment.html>


More information about the cfe-dev mailing list