Libfxcg is by no means perfect.
I would normally just submit a pull request however there is no guarantee that affect people will be aware that it is a bug in libfxcg and not their code and how to fix it. I have long had these fixed in my fork but never bothered to really document my changes. I think having a topic will get noticed by more people so that they can too make these fixes and point out any other bugs that they may have found.
All bugs listed here affect the most recent version of libfxcg as of the time of writing this post and can be found here: https://github.com/Jonimoose/libfxcg
Of course older versions are affected as well. I know for a fact that the linker script fix affects even the old PrizmSdk 0.3 from 2011 located here http://www.cemetech.net/news.php?id=486 I could not see if other bugs affect this version as the source is not included for it's libc and I have not made tests for it and see no need to as it is obsolete.
Lets not limit ourselves to bugs or terrible code that affect both. If you see a bug that affects only libfxcg it is best reported. Really no-one should be using the old PrizmSdk 0.3 from 2011 however should you find a bug that affects it and you want to post it go ahead it may give people another reason to upgrade.
1. fread is broken.
The way fread should work is that every time it is called the data following the read data is read the next call. However the function will always read from the beginning of the file. As of writting the file located here https://github.com/Jonimoose/libfxcg/blob/master/libc/stdio.c says in fwrite

Code:

 size_t ret = Bfile_ReadFile_OS(handle_tonative(stream->fileno), buffer, n, 0);

However it should be

Code:

    size_t ret = Bfile_ReadFile_OS(handle_tonative(stream->fileno), buffer, n, -1);

The only difference is that I changed the zero to a negative one. What this means is that it continues to read where it left off.
2. Linker script does not correctly handle BSS.
When you have static variables in a library you may be surprised to find that global and static variables are not initialized. Fix this by changing

Code:

        .bss : {
                _bbss = . ;
                *(.bss) *(COMMON);
                _ebss = . ;
        } >ram

To

Code:

        .bss : {
                _bbss = . ;
                *(.bss)
                *(.bss*)
                *(COMMON)
                _ebss = . ;
        } >ram

The reason why this works is that the linker will insert things such as .bss_variable_name when compiled in a library. This puts it in the proper section and upon start-up it will be cleared just like it should.
3. The memove implementation is terrible.
Actually I had worse insults that I was tempted to put but I am sure whoever wrote it makes better code by now and I do not want to hold this against them but

Code:

void* memmove(void* destination, const void* source, size_t num) {
   void* d = malloc(num);
   memcpy(d, source, num);
   memcpy(destination, d, num);
   free(d);
   return destination;
}

Yes that is right, I did not make this code up for slander purposes. It is really in there in string.c
Lets replace it with something better

Code:

void *memmove(void *dst, const void *src, size_t count){
   //From dietlibc
   char *a = dst;
   const char *b = src;
   if (src!=dst){
      if (src>dst){
         while (count--) *a++ = *b++;
      }else{
         a+=count-1;
         b+=count-1;
         while (count--) *a-- = *b--;
      }
   }
   return dst;
}

The reason it is considered a bug is because if you need to copy something larger than the small heap the function will fail.
4.The exit function crashes the calculator on purpose.

Code:

void exit(int status) {
    fprintf(stderr, "TERMINATED (%i)", status);
    // We don't have a clean way to exit (right now), so just crash it.
    ((void (*)())1)(); // Unaligned instruction
}

Actually we do have a clean way to exit. When this function is called there is usually a problem so the user should be able to see the error code. To do this we print the error message and use the GetKey function, from there the user can press the menu key when they are done reading the error code so just replace it with:

Code:

void exit(int status) {
   fprintf(stderr, "TERMINATED (%i)\nPress menu key to exit\n", status);
   int key;
   while(1)
      GetKey(&key);
}

Also edit the header stdlib.h change

Code:

void exit(int status);

to

Code:

void exit(int status) __attribute__ ((noreturn));

Also while you are there fix the abs definition so that it matches the source code.
Change

Code:

long abs(long n);

To

Code:

int abs(int x);

And now add #include <stdlib.h> to the top of stdlib.c
The reason for doing this is so that when compiling stdlib.c gcc knows that this function does not return in addition to the program you compile with gcc and libfxcg that involves exit. Yes we could just duplicate the __attribute__ ((noreturn)) to also be in stdlib.c but I feel that this is a cleaner solution. Also if stdlib.c fails to compile due to you including it, that means the headers suck and need improvement which is why I fixed the abs definition.
5. You cannot actually see the errors.
I don't really consider this a bug per say, however I believe it is much better to be able to see the error messages on screen instead of sending anything from stderr to the serial port.
So replace both fwrite_term and fwrite with

Code:

static size_t fwrite_term(const void *ptr, size_t size, size_t nitems,FILE *stream,int col){
   static int termXfxcg,termYfxcg;
       char *buffer = alloca(1 + nitems * size);
   if (buffer == NULL) {
      IOERR(stream, ENOMEM);
      return 0;
   }

   memcpy(buffer, ptr, nitems * size);
   buffer[nitems * size] = '\0';
   const char *outp = buffer;
   char *eol;

   // Loop over all lines in buffer, terminate once we've printed all lines.
   do{
      eol = strchr(outp, '\n');
      if(eol) {
         *eol = '\0';
      }

      // Cast to wider type for correct pointers
      PrintMiniMini(&termXfxcg, &termYfxcg, outp, 0, col, 0);

      // CR/LF if applicable
      if(eol){
         termXfxcg = 0;
         termYfxcg += 10;
         outp = eol + 1;
      }
      if(termYfxcg>=200)
         termYfxcg=0;
   }while (eol);
   return nitems;
}
// TODO make ptr, stream restrict for optimization
size_t fwrite(const void *ptr,size_t size,size_t nitems,FILE *stream){
   if (isstdstream(stream)) {
      if(stream->fileno==2){
         // stderr: display but red font
         //return fwrite_serial(ptr, size, nitems, stream);
         return fwrite_term(ptr, size, nitems, stream,TEXT_COLOR_RED);
      }else if(stream->fileno==1){
         // stdout: display
         return fwrite_term(ptr, size, nitems, stream,TEXT_COLOR_BLACK);
      }else{
         // stdin..?
      }
   }
   // TODO this must be able to fail, but how?
   Bfile_WriteFile_OS(handle_tonative(stream->fileno), ptr, size * nitems);
   return nitems;
}

Now in stdio.h remove the lines that say

Code:

 unsigned short termx, termy;

6. fopen is also broken.
It is common knowledge that forgetting to null terminate a string that should be null terminated will cause a bug.
Look for:

Code:

 Bfile_StrToName_ncpy(chars16, path, plen);

and replace it with

Code:

 Bfile_StrToName_ncpy(chars16, path, plen+1);

This will null terminate the string.
While this is excellent, I hope you are also planning to submit a pull request so that once people are aware of these bugs, they can grab a repaired libfxcg from the main repo that has the necessary fixes. Thanks for sharing your discoveries!
It appears memcmp is broken too, at least for me.
I fixed it in my fork of libfxcg, this is the commit:
https://github.com/gbl08ma/libfxcg/commit/006807adb72ba73a72df0de11820e5dcee0fa831#diff-d41d8cd98f00b204e9800998ecf8427e

The implementation I copied is in the public domain.
strtol is incomplete. Replace it with

Code:

#if __WORDSIZE == 64
#define ABS_LONG_MIN 9223372036854775808UL
#else
#define ABS_LONG_MIN 2147483648UL
#endif
long int strtol(const char *nptr, char **endptr, int base)//From dietlibc
{
  int neg=0;
  unsigned long int v;
  const char*orig=nptr;

  while(isspace(*nptr)) nptr++;

  if (*nptr == '-' && isalnum(nptr[1])) { neg=-1; ++nptr; }
  v=strtoul(nptr,endptr,base);
  if (endptr && *endptr==nptr) *endptr=(char *)orig;
  if (v>=ABS_LONG_MIN) {
    if (v==ABS_LONG_MIN && neg) {
      errno=0;
      return v;
    }
    errno=ERANGE;
    return (neg?LONG_MIN:LONG_MAX);
  }
  return (neg?-v:v);
}

And remove the function called strtol_consume
I have not tested them, but it appears that the tolower and toupper implementations in libfxcg are broken too.

Let's take a look at their current form:

Code:
int toupper(int c) {
   return islower(c) ? c - 65 : c;
}

int tolower(int c) {
   return isupper(c) ? c + 65 : c;
}


Shouldn't 65 be 32? If not, can someone please explain why?

Now, in the same ctype.c file, let's look a bit above:


Code:
int isxdigit(int c) {
   return isdigit(c) || ((c >= 'a' && c <= 'h') || (c >= 'A' && c <= 'H'));
}


This function is supposed to check for hexadecimal digits. To make sure I wasn't going crazy about what makes a hex digit and the purpose of the function, this page confirms it: http://www.cplusplus.com/reference/cctype/isxdigit/

Now, can someone please confirm that the current implementation is broken, and if not, explain how, according to the quoted implementation, g, G, h or H are not hexadecimal digits.
For the latter, I suspect that was copied out of an icon editor that allowed G/g and H/h to specify two different types of compression or transparency in ASCII-encoded hexadecimal. I'm confident that Shaun knows which digits hex allows. Wink
Not feeling well however the memmove implementation is making me more sick so here is one I wrote also includes a quick test

Code:

#include <stdio.h>
#include <string.h>
void*memmovemy(void*dst,const void*src,size_t n){
   if(src<dst){
      unsigned*d=dst;
      const unsigned*s=src;
      unsigned char*d8=d;
      const unsigned char*s8=s;
      while((unsigned)s8&3){
         *d8++=*s8++;//It is done like this due to SH's move instruction then postincrement address
         --n;
      }
      d=d8;
      s=s8;
      while(n>=4){
         *d++=*s++;
         n-=4;
      }
      if(n){
         d8=d;
         s8=s;
         while(n--)
            *d8++=*s8++;
      }
   }else if(src>dst){
      unsigned*d=dst+n;
      const unsigned*s=src+n;
      unsigned char*d8=d;
      const unsigned char*s8=s;
      while((unsigned)s8&3){
         *(--d8)=*(--s8);//It is done like this due to SH's preincrement address then move instruction
         --n;
      }
      d=d8;
      s=s8;
      while(n>=4){
         *(--d)=*(--s);
         n-=4;
      }
      if(n){
         d8=d;
         s8=s;
         while(n--)
            *(--d8)=*(--s8);
      }
   }
   return dst;
}
int main(void){
   unsigned char tmp[32];
   unsigned char tmp2[32];
   unsigned i;
   memset(tmp,0,16);
   memset(tmp+16,255,16);
   memmovemy(tmp+16,tmp,16);
   for(i=0;i<32;++i)
      printf("%u, ",tmp[i]);
   memset(tmp+16,255,16);
   memmovemy(tmp,tmp+16,16);
   putchar('\n');
   for(i=0;i<32;++i)
      printf("%u, ",tmp[i]);
   putchar('\n');
   memset(tmp,127,32);
   memmovemy(tmp2,tmp,32);
   for(i=0;i<32;++i)
      printf("%u, ",tmp2[i]);
   putchar('\n');
   return 0;

}

I will do more later but not today.
Edit:Fixed the code
KermMartian wrote:
For the latter, I suspect that was copied out of an icon editor that allowed G/g and H/h to specify two different types of compression or transparency in ASCII-encoded hexadecimal. I'm confident that Shaun knows which digits hex allows. Wink
Yup. Sloppy copy and paste. Good thing I'm not a doctor.
Well what I did was create a new fork of libfxcg that contains only non copyleft code and I kept my old repo on github but had to delete my old fork and push it as a "new" repo as github allows only one fork. I already submitted a pull request containing the non controversial changes that I made.
I'm a bit lost, but today, if I want to help a bit in the developpemment of libfxcg (by testing it to find eventuals bugs or even, sometimes a small pull request if I found something I could do), if you need some help for sure, what fork should I look for ? Or what is the actual direction taken by libfxcg ?
Well as of now we are working on developing libfxcg to be a BSD 3-clause licensed C library for the libfxcg the primary development direction is bug fixes although I am planning on adding more examples. As for what fork you should look for the answer is none use the upstream version: https://github.com/Jonimoose/libfxcg
You should fork the main project (by Jonimoose). It makes no sense to fork a fork as then it may be harder to get a conflict-free pull request against the main repo. For my part, I try to pull as much as possible back to the main project.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement