STRPTR returning zero

Forum for discussion about the documentation project.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: STRPTR returning zero

Post by caseih »

To the OP, why are you using strptr anyway?
jevans4949
Posts: 1186
Joined: May 08, 2006 21:58
Location: Crewe, England

Re: STRPTR returning zero

Post by jevans4949 »

caseih wrote:To the OP, why are you using strptr anyway?
Scanning text, in this case trying to separate an apartment number from the name of the block. Define a union of zstring ptr and ubyte ptr, then use the ubyte ptr to check for a string of numerics - asc("0") thru asc("9"). It's quicker than using string compare functions.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: STRPTR returning zero

Post by caseih »

Since FB automatically casts a dynamic string to a zstring ptr on demand, you could do something like this and avoid explicit strptr calls:

Code: Select all

sub process_line(l as zstring ptr)
	dim l as integer
	if l <> 0 then 'check for NULL since empty dynamic strings have NULL pointers
		slen = len(l)
		'do something with it
	end if
end sub

dim x as string
x = "Some line to parse"
process_line(x)
x = ""
process_line(x)
And actually any time you're dealing with zstring ptrs, whether from strptr or not, checking for NULL is always a good idea, though I think that FB's strings should never have null pointers. An empty string should return a pointer to a real memory location that contains a NULL end of line character. Just to make the automatic conversion between strings and zstrings more complete.
jevans4949 wrote:Scanning text, in this case trying to separate an apartment number from the name of the block. Define a union of zstring ptr and ubyte ptr, then use the ubyte ptr to check for a string of numerics - asc("0") thru asc("9"). It's quicker than using string compare functions.
Wow that's very complicated. Are you sure this is the best way to do this? Have you profiled the execution of your program to determine that this particular string processing is the bottleneck? I suspect it's not. If your program is I/O bound than spending a few extra cycles to use FB's built-in string handling is not going to cost you anything. To me the simplest solution is going to be the better solution and less error prone.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: STRPTR returning zero

Post by fxm »

Yet everything seems to be fine:

Code: Select all

Dim As String s = ""
Print "'" & *Strptr(s) & "'"
Print Len(*Strptr(s))
Print Sizeof(*Strptr(s))

Dim As Zstring * 10 z = "FreeBASIC"
Print "'" & z & "'"
z = *Strptr(s)
Print "'" & z & "'"

Sleep

Code: Select all

''
 0
 1
'FreeBASIC'
''
But except for that:

Code: Select all

Print (*Strptr(s))[0]
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: STRPTR returning zero

Post by caseih »

Hmm, interesting. It does appear to work with FB's built-in string handling, but when you hand off these empty strings to external, C-based routines, it's going to blow up. This is a bug in my opinion.

Here's an interesting program that shows this conflicting behavior:

Code: Select all

#include "crt.bi"
dim as string a
a="hello"
a=""
print strptr(a)
print "'" & *(strptr(a)) & "'"

sub test(b as zstring ptr)
    print *b 'probably okay but it won't actually print out for me
    printf(!"%s\n",b) 'this obviously segfaults
end sub

print "---"
test (a)
Why does the first print statement even work? We know strptr(a) returns NULL, yet somehow we can dereference it and print it? In my opinion, the fact that the first print statement works at all is itself a bug. It should fail, given that the pointer really is 0. Also the len(*strptr("")) should also fail with a segfault.

Looking at the compiler output, it seems what is happening is that the runtime has print and len functions specifically for zstring ptrs and when you do something like len(*strptr("")), the dereference is actually removed by the compiler and it turns it into something more like this: fb_StrLen(strptr("")), and there's internal logic in that runtime function that just returns 0 if the length is zero. So this explains why the print statement worked, and why len works on the null pointers. To me this is questionable behavior as it hides NULL pointer problems. This is clearly a bug in FB, but I'm not sure the best fix for it. The entire problem could be avoided by always making sure strings, even empty strings have some memory associated with them, and have a intrinsic null character. Then a NULL pointer reference to print or len could result in a runtime error, which would be more in line with expected behavior.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: STRPTR returning zero

Post by fxm »

More generally concerning a dereferenced null Zstring Ptr

It seems that compiled code considers (except one case) a dereferenced null Zstring Ptr as an empty Zstring:
  • Dim As Zstring Ptr
    Dim As Zstring * 1 z
    • (*pz) is considered as (z).
The only case where program aborts is when attempting to indexing a dereferenced null Zstring Ptr:
  • (*pz)[0]
See code example below:

Code: Select all

Dim As Zstring Ptr pz
Print "'" & *pz & "'"
Print Len(*pz)
Print Sizeof(*pz)

Dim As Zstring * 10 z = "FreeBASIC"
Print "'" & z & "'"
z = *pz & z
Print "'" & z & "'"
z = *pz
Print "'" & z & "'"
*pz = "a"
Print "'" & *pz & "'"

'Print (*pz)[0]  '' aborting only when indexing a dereferenced null zstring ptr

Sleep

Code: Select all

''
 0
 1
'FreeBASIC'
'FreeBASIC'
''
''
If that behavior is wanted? If yes, why not!
But when compiling such code with '-exx' option, it would be better in my opinion to have an error at runtime.

dkl, what is your opinion?
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: STRPTR returning zero

Post by Tourist Trap »

fxm wrote: It seems that compiled code considers (except one case) a dereferenced null Zstring Ptr as an empty Zstring
My feeling is that it make the code using such a mechanism still meaningful, and above all the program less prone to crash. This is like additional security, based on the fact that this is not stupid to considere null zstring ptr as an empty string.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: STRPTR returning zero

Post by caseih »

I think treating a NULL zstring ptr as a zero-length string by FB's runtime is a very bad idea. The main reason is that the moment you hand off an empty dynamic string to a function defined in an external library, it's going to crash and the programmer isn't going to know why. There are very valid reasons for having empty strings and passing them to functions. And code like this is just obviously wrong, but FB silently allows it:

Code: Select all

dim b as zstring ptr
b = 0

print *b
The above code works, contrary to all expectations of how pointers work. In my opinion, this kind of dereferencing should blow the program up with a runtime error. It certainly will blow things up the moment you try to use an external library with it.

But more critically, and this goes back to the OP's original problem, FB's handling of zero-length dynamic strings is broken. An empty string should have real memory associated to it with a null terminator byte for easy casting to zstring ptr when dealing with external functions. Seems to me this idea of letting the memory go when assigning an empty string is an optimization that was never really necessary. I haven't had time to go into the runtime library, but I would like to alter it and make a patch to get rid of this bad behavior. Should I file a bug report in the tracker?
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: STRPTR returning zero

Post by caseih »

Tourist Trap wrote:My feeling is that it make the code using such a mechanism still meaningful, and above all the program less prone to crash. This is like additional security, based on the fact that this is not stupid to considere null zstring ptr as an empty string.
But this isn't additional security. This is actually making things much worse by hiding the NULL pointer problem. Far better to crash with a runtime error so you know what the problem actually is, rather than going for weeks, months, or years with hidden modes of failure in your program. Especially if the source of the pointer is from somewhere other than FB's dynamic string descriptor.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: STRPTR returning zero

Post by fxm »

For my part I would wish at least the runtime error code 7 (Null Pointer Access) on any dereferencing of null zstring pointer when one compiles with the '-exx' option.
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: STRPTR returning zero

Post by Tourist Trap »

fxm wrote:For my part I would wish at least the runtime error code 7 (Null Pointer Access) on any dereferencing of null zstring pointer when one compiles with the '-exx' option.
Yes that would be elegant from -exx switch to give this info.
caseih wrote:This is actually making things much worse by hiding the NULL pointer problem.
I would agree with you, but maybe a null zstring ptr can be considered as equivalent of the null string. I don't know, but it seems that zstring only occures in the context of strings, so it may not be like for the pointers in general, where null means absolutely nothing clear.
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: STRPTR returning zero

Post by dkl »

I don't really see a problem, maybe a small inconsistency at best...

Printing *myStringPtr or *myZstringPtr will call the Print function and pass the string Byref, and as it happens, it checks for NULL, and prints nothing in that case. That's a pretty good way of dealing with that problem, don't you think? Alternatively it could crash, or print something like "(null)" like some CRTs' printf() does. But that seems worse to me than printing nothing.

And consider this:

Code: Select all

sub f(byref i as integer)
end sub

dim pi as integer ptr = 0
f(*pi)
You can pass a NULL reference, and it won't crash or be caught by -exx until accessed.

Or another, related case:

Code: Select all

type UDT
	as integer a, b, c
end type

print @cptr(UDT ptr, 0)->c
That's how offsetof() is implemented, should -exx catch that too? There's a NULL pointer dereference in the source code, but not in the final program. Maybe that's the main inconsistency issue here?
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: STRPTR returning zero

Post by fxm »

And for that, one special case?

Code: Select all

Dim As Integer Ptr pi = 0
Dim As Integer i= 1
'i = *pi  '' runtime error 7 (null pointer access)

Dim As Zstring * 10 z = "FreeBASIC"
Dim As Zstring Ptr pz = 0
z = *pz  '' ok
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: STRPTR returning zero

Post by Tourist Trap »

fxm wrote:

Code: Select all

z = *pz  '' ok
As I understand *pz return the null string if pz=0.
In the case of an integer, I don't know why but it wouldn't make sense for me, but for strings it seems ok. But I suppose that a null pointer could in the absolute be dereferenced with a conventional value (default or other).
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: STRPTR returning zero

Post by fxm »

dkl wrote:

Code: Select all

type UDT
	as integer a, b, c
end type

print @cptr(UDT ptr, 0)->c
That's how offsetof() is implemented, should -exx catch that too? There's a NULL pointer dereference in the source code, but not in the final program. Maybe that's the main inconsistency issue here?
That seems normal that the runtime check (requested by '-exx') to test the null pointers works only for the variables and not for the constants or literals (at worst these last could being processed at compile time).
Post Reply