3

During a discussion today I came across that there are checks in the VxWorks and in LynxOS which tells you that the address you assign for a pointer is from a valid range. This the first time I am hearing about this code like I assign int *i=&variable;.

I should get a warning or error which says that In my application I cannot assign the address value to the integer.

Like while I do a NULL check I am only checking the address 0x00000000. But there can be the case the address might be 0x00000001. Which is also an invalid case if its an unmapped area and might not be accessible. Is any one aware of some thing similar for Linux or can guide how its done in VxWorks or LynxOS.

Any ideas??

Alejandro Montilla
  • 2,626
  • 3
  • 31
  • 35
achoora
  • 1,270
  • 1
  • 16
  • 32

3 Answers3

6

The function you seek in VxWorks is called vxMemProbe.

Basically the vxMemProbe libraries insert special exception handling code to catch a page fault or bus error. The vxMemProbe function is used to check if the address is valid for read or write. It also allows you to test if the particular address is accessible with a given data width (8,16,32,64 bits) and alignment.

The underlying mechanism of vxMemProbe is tied to the specific architectures exception handling mechanisms. The vxMemProbe libraries insert code into the exception handlers. When you probe an address that triggers an exception the handler checks to see if vxMemProbe triggered the exception. If so, then the handler restores the state processor prior to the exception and returns execution to where vxMemProbe was called while also returning value via the architectures given calling conventions.

vxWizard
  • 576
  • 2
  • 3
3

There are several misconceptions here:

  • From the perspective of the language C, there's only one pointer value that's guaranteed to be invalid, and this is NULL. For other values, it depends on the context. A pointer is valid when it points to an object that is currently alive. (Note that this is trivially true in your int *i = &variable example, as this is only valid syntax when there is a variable accessible from your current scope)

  • NULL does not necessarily mean a value with all bits zero. This is the most common case, but there can be platforms that use a different bit pattern for the NULL pointer. It's even allowed by the C standard that pointers of different types have different representations for NULL. Still, converting 0 to a pointer type is guaranteed to result in the NULL pointer for this type.

  • I don't know what exactly you're referring to in VxWorks, but of course Linux checks memory accesses. If a process tries to access an address that's not mapped in the virtual address space, this process is sent a SIGSEGV signal, which causes immediate abnormal program termination (Segmentation fault).

  • on many systems (including Linux & windows) you can have your own signal handling and not necessary it has to end the program. You may have procedures to recover from those events – 0___________ Aug 23 '17 at 13:24
  • @PeterJ_01 that's most of the time a **very bad idea** and there's no portably working way to recover from `SIGSEGV` anyways. Why bother, if you're sent such a signal, your program has a bug. –  Aug 23 '17 at 13:30
  • `NULL does not necessary mean a value with all bits zero` according to the standard it has to. It allows IMO ridiculous `if (p)` or `if (!p)` checks. – 0___________ Aug 23 '17 at 13:30
  • 2
    @PeterJ_01 wrong again. the `NULL` pointer evaluates to false in a boolean context, no matter what its representation is. –  Aug 23 '17 at 13:31
  • 3
    @PeterJ_01: no the compiler could emit special tests for such cases. – Basile Starynkevitch Aug 23 '17 at 13:31
  • 1
    @Felix Palmen `An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66)` – 0___________ Aug 23 '17 at 13:37
  • 1
    @Felix Palmen just took a quick look. Where in the standard is this behaviour described? `wrong again. the NULL pointer evaluates to false in a boolean context, no matter what its representation is` – 0___________ Aug 23 '17 at 13:39
  • @Basile Starynkevitch `no the compiler could emit special tests for such cases` I do not understand. It is about the signal handler not the signal itself – 0___________ Aug 23 '17 at 13:45
  • 1
    @PeterJ_01 exactly in the part you cite. A **cast** is an explicit conversion, there's **nothing** said about the representation of this *null pointer*. An **expression** is entirely different from a **representation**. –  Aug 23 '17 at 13:46
  • 1
    What I mean is that on the few weird [ISA](https://en.wikipedia.org/wiki/Instruction_set_architecture)s (I can't name any one) where `NULL` is *not* an all-zero bits word, the C compiler would emit ipso facto specific code to test the nullity of a pointer. – Basile Starynkevitch Aug 23 '17 at 13:46
  • Standard does not say anything about use of the lonely pointer in the boolean expressions. Only about two of them. And IMO no compiler will add any code to check it. – 0___________ Aug 23 '17 at 13:51
  • @PeterJ_01: However, `gcc -fsanitize=address` *is adding* code to check most addresses. – Basile Starynkevitch Aug 23 '17 at 13:53
  • That `-fsanitize=address` option also exists in [Clang](http://clang.llvm.org/). But my point is that sometimes a compiler could add code to check addresses. – Basile Starynkevitch Aug 23 '17 at 13:59
  • @PeterJ_01 then your opinion is just wrong. See **§6.5.3.3p5** and **§6.5.9p5**. Together, `!p` translates to `p != 0` and this `0` is taken as a *null pointer constant*. –  Aug 23 '17 at 13:59
  • 1
    See also the [C FAQ on NULL](http://c-faq.com/null/) (with references to the standard, but already explained) –  Aug 23 '17 at 14:01
  • And everything to avoid `p != NULL` or `p == NULL` which makes code more human readable. – 0___________ Aug 23 '17 at 14:02
  • @PeterJ_01 I state the exact opposite ... very often, a simple `!p` is much closer to the *semantics* of the code. –  Aug 23 '17 at 14:02
  • And does not work on any ARM Cortex project as the address 0 is valid there. or avr8 – 0___________ Aug 23 '17 at 14:18
  • @PeterJ that would be a compiler bug (and would mean `!= NULL` wouldn't work either). If an all-bits-zero value is a valid pointer, it can't be used for a null pointer representation. –  Aug 23 '17 at 14:21
  • compilers just follow the Standard. in many parts the quality if it is disputable - but of course it is a purely scholastic discussion with no practical use. I someone needs to read the address 0 knows how to do it and what the potential consequences are. – 0___________ Aug 23 '17 at 14:25
  • As always, you just refuse to learn something. If your opinions disagree with the factual world, it's probably not the world that's wrong. Enough said. –  Aug 23 '17 at 14:27
3

In general you can't do what you want, as explained in Felix Palmen's answer.

I should get a warning or error which says that In my application I cannot assign the address value to the integer.

Statically and reliably detecting all pointer faults is impossible (because it could be proven equivalent to solving the halting problem). BTW you might consider using static program analysis tools like Frama-C.

On Linux, in principle, you might test at runtime if a given address is valid in your virtual address space by e.g. using /proc/, e.g. by parsing the /proc/self/maps pseudo textual file (to understand what I mean try cat /proc/$$/maps in a terminal, then cat /proc/self/maps). See proc(5). In practice I don't recommend doing that often (it probably would be too slow), and of course it is not a builtin function of the compiler (you should code it yourself). BTW, be aware of ASLR.

However, there are tools to help detect (some of) the faulty address uses, in particular valgrind and the address sanitizer facility, read about instrumentation options of GCC and try to compile with -fsanitize=address ...

Don't forget to compile your code with all warnings and debug info, so use gcc -Wall -Wextra -g to compile it.

BTW, if you store in some global pointer the address of some local variable and dereference that pointer after that local variable is in scope, you still have some undefined behavior (even if your code don't crash, because you usually dereference some random address on your call stack) and you should be very scared. UB should be always avoided.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547