lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Tim Hill once stated:
> 
> On Oct 1, 2013, at 6:51 PM, Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br> wrote:
> 
> >> I still feel the lack of an efficient way to determine if a table t is
> >> a sequence is a significant hole in the language/runtime.
> > 
> > Why would you need that? If you care that a table is a sequence, then
> > either you have created the table and know it or you have been handed a
> > table and can assume whoever gave you the table honors the contract with
> > you to use only sequences. What am I missing?
> > 
> 
> Seriously??? I'm stunned that you can seriously suggest "honors the
> contract with you to use only sequences". So if a 3rd party makes an error
> calling an API, it's ok to crash or generate random erroneous results?

  It depends upon the context of the program.  

  At one point, a daemon I wrote [1] would catch SIGSEGV, log the condition,
save its current state and exit.  And yes, it did just that.  Then I
realized: if the program generated a SIGSEGV, it was most likely due to a
programming error leading to subtle memory corruption and thus, the state
I'm saving out could potentially be bogus (garbage in, garbage out).  Better
to just log the condition and exit and skip saving any data.  Even
better---don't bother with catching the SIGSEGV.  Instead, have a parent
process wait for the child to exit, and report the SIGSEGV that way [2].

  In my own coding, For data coming in outside the program, from files, from
a network connection, where ever, I check the crap out of it [8].  But in
all other cases, and even in library code I write, I make the following
assumption:

	You will give me good data.  I will do my best to give you good data
	in return.

  So, I wrote the function:

	dns_class_t dns_class_value(const char *tag);

it doesn't check the pointer being passed in.  Give it a NULL, it will
happily crash.  You might not agree, but here's my reasoning for this
behavior:  defensive programming hides bugs.  Why are you passing a NULL
pointer in?  Where did that NULL pointer come from?  It doesn't even make
sense (in my opinion) to pass a NULL to this routine.  So, passing in NULL
(again, in my opinion) is a bug.  And thus, I will crash hard.  And fast
(that is, unless you catch SIGSEGV).  

  Yes, you could do:

	dns_class_t wrapper_dns_class_value(const char *tag)
	{
	  if (tag == NULL)
	  {
	    /* um ... erm ... */
	    return CLASS_UNKNOWN; /* okay?  Maybe? */
	  }
	  else
	  {
	    return dns_class_value(tag);
	  }
	}

  No, that's not quite right.  Okay ...

	int wrapper_dns_class_value(dns_class_t *pclass,const char *tag)
	{
	  if (pclass == NULL)
	  {
	    return MYERR_BAD_CLASS_POINTER;
	  }
	  
	  if (tag == NULL)
	  {
	    return MYERR_BAD_TAG_POINTER;
	  }

	  *pclass = dns_class_value(tag);
	  return 0;
	}

  which works, until a user of your library wrapping my library fails to
check the return code of wrapper_dns_class_value() and uses whatever bogus
value that's in *pclass and has to spend several hours chasing down the fact
that they failed to check the return code from your function (or worse, get
you to rewrite the code a bit:

	if (tag == NULL)
	{
 	  *pclass = CLASS_UNKNOWN;
	  return MYERR_BAD_TAG_POINTER;
	}

because they don't want to be bothered with checking the return code.

  My version---just ensure I get a valid pointer and this mess goes away.

> Where in Lua is this behavior exhibited? Is it ok for load() to skip over
> syntax errors and create an executable chunk that runs random, invalid, VM
> code? Is it ok for math.sin() to generate random values if I supply a
> boolean or (non numeric) string as input?

	"On two occasions I have been asked, 'Pray, Mr. Babbage, if you put
	into the machine wrong figures, will the right answers come out?' I
	am not able rightly to apprehend the kind of confusion of ideas that
	could provoke such a question."
		-- Charles Babbage

> Scenario: I'm writing a 3rd party API that expects a sequence as an
> argument. For example:
> 
> sum = addSeq(t)
> The addSeq() function adds all the values in the sequence in the table t,
> returning the total.
> 
> What should the API do if "t" is NOT a sequence:
> (a) Return a random result that is incorrect (or crash)
> (b) Flag an error

  Is a sequence of 0 elements valid?

  So, what exactly is wrong with:

	sum = 0
	for i = 1 , #t do
	  sum = sum + t[i]
	end

  I mean, besides not checking if each element is a number and not NaN (but
then again, you can't check for NaN because NaN ~= NaN and there goes your
entire calculation out the window ... )

  -spc (Who does not like writing defensive code, but instead goes for
	offensive code ... oh wait a second ... )

[1]	http://www.x-grey.com/

[2]	It could be argued that by catching SIGSEGV, the program can then
	generate a crash report with enough context to hopefully diagnose
	the issue.  And surprisingly, it's fairly easy to generate a stack
	trace under Linux [3] but even though I can generate crash reports
	[4] there are still some issues to deal with---namely, if the stack
	pointer is corrupted (say, somehow, ESP [5] which causes the
	segfault, how in the world is crash_report() supposed to work?

	Well, I could set up a predefined stack for the signal handler, but
	then, on non-Linux systems I get an incorrect stack dump [6].  But
	to get a correct stack dump, I need to run the risk that the stack
	pointer [5] is still valid [7].

[3]	http://boston.conman.org/2013/01/11.1

[4]	https://github.com/spc476/CGILib/blob/master/src/crashreport.c

[5]	x86.  On x86-64, this would be RSP.  On the Motorola 68k series,
	this is A7.  On the VAX, R14.  

[6]	Linux does some tricks to handle this case when calling backtrace().

[7]	I just realized that when I generate the stack dump, I don't
	actually check to see if the stack pointer I'm using is NULL. 
	That's an easy fix, but what if ESP [5] wasn't NULL but wasn't a
	valid pointer?  How do I check that?

[8]	I do this in SPCDNS [9] and I'm quite strict about it.  And so far,
	it's found several bugs in other DNS implementations.

[9]	https://github.com/spc476/SPCDNS

[10]	The C version of assert().