mq_send: glibc forces param 2 to be nonnull - gcc

My static code analysis has found a bug in my code. I try to send an empty message:
mq_send(mqId, 0, 0, 1);
It says, the message buffer (parameter 2) should not be 0. It says this because the header says so:
glibc-2.29/rt/mqueue.h
/* Add message pointed by MSG_PTR to message queue MQDES. */
extern int mq_send (mqd_t __mqdes, const char *__msg_ptr, size_t __msg_len,
unsigned int __msg_prio) __nonnull ((2));
glibc-2.29/sys/cdefs.h
/* The nonull function attribute allows to mark pointer parameters which
must not be NULL. */
#if __GNUC_PREREQ (3,3)
# define __nonnull(params) __attribute__ ((__nonnull__ params))
#else
# define __nonnull(params)
#endif
I know how to fix this. I just wonder: is this correctly implemented in glibc?
Neither linux man nor the posix standard says anything about passing a nullpointer. No error code or undefined behavior is described. In fact, when the length is 0, a null pointer is totally valid and works!

Related

__eeprom and EEMEM

I am trying to port a code base from iar to avr-gcc. Amongst other things that have to replaced, the iar eeprom memory attribute __eeprom has to replaced with a avr-gcc friendly attribute. AFAIK the replacement for that is EEMEM, but the usage differs and I am not able to figure out how to replace __eeprom in the cleanest manner.
../src/myfunc.h:35:46: error: section attribute not allowed for 'src'
UBYTE *strcpye(UBYTE *dest, UBYTE EEMEM *src);
This error is not limited to pointers, but to all variables in general. IMO the usage of EEMEM is correct, where am I going wrong?
In the avr-gcc toolchain, avr-libc defines macro EEMEM in avr/eeprom.h:
#define EEMEM __attribute__((section(".eeprom")))
This means it's just an attribute that determines the section in which an object with this attribute will be located. In particular, EEMEM only makes sense for variables in static storage. Moreover, accesses to objects located in EEMEM have to be done by hand using functions / macros supplied by avr/eeprom.h like
void eeprom_read_block (void *dst, const void *src, size_t n);
void eeprom_write_byte (uint8_t *p, uint8_t value);
void eeprom_update_word (uint16_t *p, uint16_t value);
etc. Also notice that EEMEM is just an attribute and not a qualifier (like __flash for example). This means that even though you can tag a pointer (target) using attributes, that won't change the access in any way. To be more specific, any access through a pointer that's attributed EEMEM will be to RAM and not to eeprom.
In your case, the prototype of strcpye would read
char* strcpye (char *dest, const char *src);
and the implementation of that function would apply eeprom_read_byte on src++ and write to dest++ until it reads a terminal \0. Notice that you might need an explicit pointer cast as eeprom_read_byte expects [const] uint8_t*, and that char, signed char and unsigned char are 3 distinct types in C.

Native C extension not finding code used by Ruby core

Based on browsing the Ruby API sources for Array#length and Range#begin I know that macros RARRAY_LEN and RANGE_BEG exist and are used to implement the corresponding methods:
Array#length
static VALUE
rb_ary_length(VALUE ary)
{
long len = RARRAY_LEN(ary);
return LONG2NUM(len);
}
Range#begin
static VALUE
range_begin(VALUE range)
{
return RANGE_BEG(range);
}
However, while the code below has no problems with RARRAY_LEN I have been unable to get RANGE_BEG to work:
test.c
#include "test.h"
VALUE rb_mTest = Qnil;
VALUE rb_cTest = Qnil;
VALUE super_initialize(VALUE self) {
return self;
}
VALUE array_len(VALUE self, VALUE ary) {
Check_Type(ary, T_ARRAY);
return LONG2NUM(RARRAY_LEN(ary)); // this works
}
VALUE range_begin(VALUE self, VALUE rng) {
if (rb_obj_is_kind_of(rng, rb_cRange)) {
// return RANGE_BEG(rng); // doesn't work
return rb_funcall(rng, rb_intern("begin"), 0); // this works
}
return Qnil;
}
void Init_test(void) {
rb_mTest = rb_define_module("RangeTest");
rb_cTest = rb_define_class_under(rb_mTest, "Tester", rb_cObject);
rb_define_method(rb_cTest, "initialize", super_initialize, 0);
rb_define_method(rb_cTest, "array_len", array_len, 1);
rb_define_method(rb_cTest, "begin_value", range_begin, 1);
}
test.h
#ifndef TEST_H
#define TEST_H 1
#include "ruby.h"
VALUE super_initialize(VALUE self);
void Init_test(void);
VALUE range_begin(VALUE self, VALUE rng);
VALUE array_len(VALUE self, VALUE ary);
#endif /* TEST_H */
When the commented line is made active, the compiler generates this error message:
error: implicit declaration of function 'RANGE_BEG' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
return RANGE_BEG(rng);
^
1 error generated.
This sounds to me like I'm missing an include, but 1) no additional include is required for RARRAY_LEN; 2) including range.h didn't change anything; and 3) I've failed to find where RANGE_BEG is defined when I tried searching with grep.
As you can see, I have a work-around using rb_funcall but would like to know why one macro found in the Ruby source works while another doesn't. The extension docs I've looked at have also implied that the macro versions are more efficient than function call versions for data access, so using the macro would be preferable.
To sum up, I'm hoping anybody can tell me a suitable incantation to get the compiler to access RANGE_BEG. This is happening on MacOS 12.4 (Monterey) using ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21] installed by HomeBrew, with CPPFLAGS=-I/opt/homebrew/opt/ruby/include and LDFLAGS=-L/opt/homebrew/opt/ruby/lib.
For whatever reason the RANGE_XXX macros are not included in the API headers. They are only defined and used in the internal Ruby implementation itself. It seems they wanted to keep these methods private, probably to ensure backwards and forward compatibility in case the internal implementation changes over time.
However, you get almost identical access through the API by using the provided method rb_range_values:
int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp);
You can peek at its implementation here, where you can see it actually makes use of those internal macros.
To use it you simply have to define the returned variables and then call:
VALUE beg;
VALUE end;
int excl;
rb_range_values(range, &beg, &end, &excl);
Although this method does a little bit more than you need, it seeems likely it is still faster than a version using funcall, but you would need to benchmark to make sure.

So how to fix warnings on this simple RAII close caller?

So I get this warning for the line:
warning: ignoring attributes on template argument ‘int (*)(DIR*) {aka int (*)(__dirstream*)}’ [-Wignored-attributes]
std::unique_ptr<DIR, decltype(closedir)*> cd(od, closedir);
So I can see the compiler hint attribute __nonnull in the spec:
/* Close the directory stream DIRP.
Return 0 if successful, -1 if not.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int closedir (DIR *__dirp) __nonnull ((1));
So why doesn't declspec copy that attribute across, and how do I make it shut up, without writing something ugly?
Posted for c++11, but I would be happy to hear "they fixed it later"

MFC - Display message

I'm trying to display a simple message within my first MFC application.
Strangely, the first sample doesn't work, instead the second one works correctly.
auto text = std::to_wstring(1).c_str();
MessageBox(text, NULL, 0); // Not ok, the message is empty
auto temp = std::to_wstring(1);
MessageBox(temp.c_str(), NULL, 0); // Ok, display 1
Can you explain why of this behavior?
Yes, in the first example, the wstring created by the call to std::to_wstring only has the scope of the line. After the line executes, it is out of scope and its value is dubious.
In the second example, the wstring is still in scope and valid and so the call to .c_str() works.
No, the other answer is wrong. Look at the implementation of c_str(). c_str() returns basically a LPCWSTR... call it a const WCHAR* or const wchar_t* or whatever. However, the return of c_str() is to an internal pointer of wstring. The problem is that after the line of code executes, the wstring returned from to_wstring() is not valid and so the the pointer returned by c_str() is garbage. For fun, try the following code:
//cstr_.cpp
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv)
{
auto temp = to_wstring(1).c_str();
wprintf(L"%s\n", temp);
auto temp2 = to_wstring(1);
wprintf(L"%s\n", temp2.c_str());
wstring ws = to_wstring(1);
auto temp3 = ws.c_str();
wprintf(L"%s\n", temp3);
}
I compiled the above from a VC++ shell prompt with: cl.exe cstr.cpp
If the other answer is correct, then the last line should have garbage or nothing output because according to the other answer, c_str() is a temp. But, if my answer is correct, then it should output 1 (which it does). If all else fails, look at the implementation source code.

warning: cast from pointer to integer of different size

I'm working on socket programming.. my code executes the way I want it to, I'm able to use it. BUT it gives me a warning on compilation.
I compile using
gcc server1.c -o server1 -lpthread
And I get the warning
warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
This error comes for the following code
int newsockfd;
newsockfd = (int)newsockfdd; //this line
And I'm using newsockfdd (which is int) in the following chunk of code
if (pthread_create(&threadID[i++], NULL, serverThread, (void *)(intptr_t)newsockfdd) != 0)
{
perror("Thread create error");
}
As you can probably tell, the code is not written too well (I am working on making it better). I know that this warning comes because of something to do with the size of int. But I really dunno how to fix it. Before I put in (intptr_t) in the pthread_create statement, it was showing a warning on that line, but that time the warning was
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
It seems like there should be a simple fix to this? But I can't find it. I'm using Ubuntu 64-bit. Is that a reason for the warning?
As has been established in the comments, the situation is (modulo renaming to avoid confusing occurrences of newsockfdd as passed argument or received parameter)
void *serverThread(void *arg) {
// ...
int newsockfd = (int)arg;
// ...
}
and in main (or a function called from there)
// ...
int newsockfdd = whatever;
// ...
if (pthread_create(&threadID[i++], NULL, serverThread, (void *)(intptr_t)newsockfdd) != 0)
// ..
So when the int newsockfdd is passed as an argument to serverThread, it is cast to a void*. Originally, that cast was direct, but the intermediate cast to intptr_t was inserted to remove the warning about the cast to pointer from integer of different size.
And in serverThread, the received void* is cast to int, resulting in the warning about the cast from pointer to integer of different size.
That warning could probably also be removed by inserting an intermediate cast to intptr_t.
But, while the standard allows casting integers to pointers and vice versa, the results are implementation-defined and there's no guarantee that int -> void* -> int round-trips (although, a footnote in the standard says
The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to
be consistent with the addressing structure of the execution environment.
so probably it will round-trip and work as intended in this case - but it would likely not work [only for values of small enough absolute value] if the size of a void* is smaller than that of the integer type [consider long long -> void* -> long long on 32-bit systems]).
The proper fix is to avoid the casting between integers and pointers,
void *serverThread(void *arg) {
// ... check that arg isn't NULL
int newsockfd = *(int *)arg;
// ...
}
in severThread, cast the received pointer to a pointer of appropriate type, and read the pointed-to value, and in main
if// ...
int newsockfdd = whatever;
// ...
if (pthread_create(&threadID[i++], NULL, serverThread, &newsockfdd) != 0)
pass the address of newsockfdd.
One caveat: if serverThread is called from multiple places, the calls in all these places need to be fixed.

Resources