# Two identical systems but clang gives warning on only one



## drhowarddrfine (Jul 27, 2019)

Well, sort of identical. I have some old threaded C code that I was tinkering with. I put it on my personal server and it compiles and runs just great. I have an old notebook where I installed FreeBSD from scratch, put the same server and everything else on it--identical to what's on the VPS. 12.0-RELEASE p8. I compile the exact same code with the same version of clang but I get a warning:

```
warning: cast to 'void *' from smaller integer type 'int'
```
It comes from this line:

```
for (i = 1; i < THREAD_COUNT; i++)
        pthread_create(&id[i], NULL, doit, (void*)i);
```
at the point (void*)i

The program works as it should on my notebook but I don't understand why there is a warning on one system but not the other. It sounds familiar, as if I've had this issue years ago, and there was a configuration somewhere that I was unaware of and now have forgotten.

So my question is not how to fix the code but why the long running system on a VPS does not give me the same warning that the new install on my notebook does?


----------



## shkhln (Jul 27, 2019)

Do you run i386 FreeBSD on VPS?


----------



## drhowarddrfine (Jul 27, 2019)

Nope. Both are amd64 though different processors.


----------



## shkhln (Jul 27, 2019)

Ok then. Is _i_ actually declared as _int_?


----------



## drhowarddrfine (Jul 27, 2019)

It is

```
int rc, i, thread_id = (int)a;
```


----------



## Alain De Vos (Jul 27, 2019)

Maybe this helps,


			Diagnostic flags in Clang — Clang 6 documentation


----------



## shkhln (Jul 27, 2019)

The obvious explanation would be either _-Wno-int-to-void-pointer-cast_ or _-m32_ flag_. _How did you verify that compilation flags are identical in both cases?


----------



## drhowarddrfine (Jul 27, 2019)

I don't know that the flags are the same except I would not have made changes to a plain install on this server.

What I mean is, I'm doing just this:

```
clang -I /usr/local/include -L /usr/local/lib -lpthread main.c
```


----------



## shkhln (Jul 27, 2019)

Can you reproduce that behavior with this code?

```
int main() {
  int   foo = 0;
  void* bar = (void*)foo;
  return 0;
}
```

If you can, then maybe try `clang -v` for more verbose output. (You don't have to post it here.)


----------



## drhowarddrfine (Jul 27, 2019)

Same warning on the notebook but not on the server. Also, with clang -v, same output on both.

EDIT: No! clang -v does show a difference.

EDIT2: I'm betting the server is confounding things. clang -v shows this:

```
-m elf_i386_fbsd
```
So now I have to investigate why the server has that set.


----------



## balanga (Jul 27, 2019)

Do you have the exact same version of FreeBSD running on both?

Can you mount (or copy) the installation from one system onto the other and then run `diff -rq dir1 dir2`.


----------



## drhowarddrfine (Jul 27, 2019)

balanga You may have missed my edits. Especially EDIT2.


----------



## balanga (Jul 27, 2019)

No... I just wondered if both were 12.0-RELEASE *p8*...


----------



## drhowarddrfine (Jul 27, 2019)

Yes, they are both p8


----------



## shkhln (Jul 27, 2019)

drhowarddrfine said:


> EDIT2: I'm betting the server is confounding things. clang -v shows this:
> 
> ```
> -m elf_i386_fbsd
> ```



I don't know of any way of getting 32-bit binaries from clang on amd64 _by default_. Other than writing a wrapper script with the same name, I suppose.


----------



## _martin (Jul 27, 2019)

You mentioned both servers are CPU amd64 and version 12p8.  But one of your clang is i386 ? What is the exact output of `uname -a` and `clang -v` from your machines ? The -m elf_i386_fbsd seems like linker flag.
Also is there a particular reason why thread_id is typecasted to int ? When it comes to pointers to int stdint(7) has generic type intptr_t which can be handy.


----------



## drhowarddrfine (Jul 28, 2019)

_martin said:


> You mentioned both servers are CPU amd64 and version 12p8.


Yes they are.


_martin said:


> But one of your clang is i386 ?


I said `clang -v` shows `-m elf_i386_fbsd` as one of the fields in the output. I don't know why and need to find out.


_martin said:


> Also is there a particular reason why thread_id is typecasted to int ?


This is old code I had found years ago and I just started looking at it today. It compiled and works as intended but I haven't spent any time understanding it.


----------



## drhowarddrfine (Jul 28, 2019)

shkhln said:


> I don't know of any way of getting 32-bit binaries from clang on amd64 _by default_.


I'm not trying to do that.


----------



## _martin (Jul 28, 2019)

Looking at your code snippets again I'm a bit confused. You mentioned it works on one machine and not the other. But if i is defined as int i then this:

```
pthread_create(&id[i], NULL, doit, (void*)i);
```
Should be really defined as

```
pthread_create(&id[i], NULL, doit, (void*)&i);
```
As you need a pointer to an arg.


----------



## shkhln (Jul 28, 2019)

drhowarddrfine said:


> I'm not trying to do that.



That's what you seem to be already doing from the answers you have provided.



_martin said:


> As you need a pointer to an arg.



Not really, it's the argument to the caller supplied callback, so the argument can be everything as long as it fits. It's the callback's job to properly interpret the argument.


----------



## drhowarddrfine (Jul 28, 2019)

Aha! Somehow, and I think I know how, the linker on my VPS is the GNU linker and not from llvm. 

A while back, I was doing more tinkering and found I filled the disk trying to have both gcc and llvm. I have a feeling I deinstalled llvm and this is the situation I'm in.  

I'll try and fix this in the morning.


----------



## shkhln (Jul 28, 2019)

drhowarddrfine said:


> the linker on my VPS is the GNU linker and not from llvm.



Not a concern. Linkers do not invoke themselves, thus this can't be the source of "-m elf_i386_fbsd" flag. (Or a compiler warning for that matter.)


----------



## _martin (Jul 28, 2019)

shkhln said:


> Not really, it's the argument to the caller supplied callback


Hm, I'm not really in the position to say yes or no here. My reply here is out of curiosity. Though I do understand that if callback function knows what to expect it can dealt with it. But shouldn't it be, according to standard at least, that if function argument defines to pass a pointer (be it void) pointer should be passed ?

I think this is where the original OP's warning is coming from - he's trying to pass int as void* - hence the size issue. He could also use (void*)(intptr_t)i which would probably silenced the warning.

EDIT: I'm attaching also the short example. bar() function being what I'd expect it should be like. 


```
#include <stdio.h>
#include <stdint.h>

void foo(void* d) {
        printf ("foo: %x\n", (int)(intptr_t)d);
}

void bar(void* d) {
        printf("bar: %x\n", *((int*)d));
}

int main() {
        int a = 0xcafec0de;

        printf ("a: %x\n", a);
        foo((void*)(intptr_t)a);
        bar(&a);

        return 0;
}
```


----------



## shkhln (Jul 28, 2019)

_martin said:


> But shouldn't it be, according to standard at least, that if function argument defines to pass a pointer (be it void) pointer should be passed ?



I don't think an average C programmer cares much about safety, standards, undefined behavior and so on. An almost free optimization on other hand…

(Note that C itself doesn't care about safety either, so it's mostly a self-selection issue.)


----------



## ralphbsz (Jul 28, 2019)

Modify your code slightly: For the variable that is an int, and the variable that is a void *, print their sizeof. That requires ignoring the warnings and running the program. Obviously, the int will have a sizeof == 4, and the void * will be == 8. You already know that, and you even know what the real source of the problem is (the i386 elf format). But this will give you a good debugging tool as you try to fix the source of the problem.

By the way, the casting style and the multiple assignments are nasty coding style, and will eventually get it in trouble. If this is supposed to be maintainable and production-worthy code, then you should invest some time in cleanup and making it pretty, because it will improve the long-term quality. On the other hand, if it is a one-off hack or an educational toy, the faster you get it done the better.


----------



## _martin (Jul 28, 2019)

shkhln said:


> I don't think average C programmer cares much about safety, standards, undefined behavior and so on.


Well, it doesn't matter what an average C programmer cares about . Here's it's about the proper way of doing things.

Though I do think warning comes from the issue I mentioned earlier it is still interesting to see why OP doesn't have this issue on one of his machines. But then again, full `uname`, `clang -v`, `file` output of the binary and even larger piece of code would clarify more things.


----------



## drhowarddrfine (Jul 28, 2019)

It's a multi-threaded implementation of FastCGI that someone gave me long ago to play with. I was told it worked, and it does, but it was just a "let's see what this does" sort of thing. So now that I have a proof of concept I can build on that.

But my misunderstanding was never about the code.


----------



## shkhln (Jul 28, 2019)

_martin said:


> Here's it's about the proper way of doing things.



It's quite idiomatic, though. Since the point of contention seems to be the potential inability to fit an integer into a pointer, you can likely throw a few assertions into your program (preferably static assert from C11):

```
static_assert(sizeof(int) <= sizeof(void*), "Oh crap");
```


----------



## unitrunker (Jul 28, 2019)

_martin - you advise to pass the address of a stack variable as the context variable to a pthread function. That is creates a nasty hard-to-diagnose bug. Apologies to drhowarddrfine for going off topic.


----------



## _martin (Jul 28, 2019)

drhowarddrfine said:


> But my misunderstanding was never about the code.


I'm curious to see why you have the warning on one system and not the other. For that it would help to see what I've mentioned. I still think the warning is stemming from casting int to void* (size of 4 to size of 8). If you passed the variable as (void*)(intptr_t)i that warning gets silenced. Maybe default behavior of each clang is different?

To compare -v of my clang shows only:


```
$ clang -v
FreeBSD clang version 6.0.1 (tags/RELEASE_601/final 335540) (based on LLVM 6.0.1)
Target: x86_64-unknown-freebsd12.0
Thread model: posix
InstalledDir: /usr/bin
$
```

unitrunker raised valid point why one passes value as argument even though it's defined as void*.


----------



## drhowarddrfine (Jul 28, 2019)

_martin said:


> I'm curious to see why you have the warning on one system and not the other.


Me, too. That's why I started this thread and asked that question. But I answered all your questions throughout this thread.

Unless something comes up, I'm going to reinstall  llvm but, again, I couldn't at one time because I needed gcc for something and I couldn't fit gcc and llvm on the small disk of the VPS. I have a feeling having gnu ld as the linker is the reason for no warning.


----------



## _martin (Jul 28, 2019)

I don't think this is related to ld, warning is coming from compiler itself. You could do `clang -c test.c` to avoid linking. I bet you'll still see the warning.

How exactly are you compiling it ? Any chance that cc points to gcc on one of the servers ?


----------

