Giter VIP home page Giter VIP logo

libcs50's Introduction

CS50 Library for C

Build Status

Development

make: builds dynamic library

make deb: builds source deb

make install: installs the library under /usr/local by default (set DESTDIR to change that)

Installation

Ubuntu

$ curl -s https://packagecloud.io/install/repositories/cs50/repo/script.deb.sh | sudo bash
$ sudo apt-get install libcs50

Fedora

$ curl -s https://packagecloud.io/install/repositories/cs50/repo/script.rpm.sh | sudo bash
$ yum install libcs50

From Source (Linux and Mac)

  1. Download the latest release from https://github.com/cs50/libcs50/releases
  2. Extract libcs50-*.*
  3. cd libcs50-*
  4. sudo make install

By default, we install to /usr/local. If you'd like to change the installation location, run sudo DESTDIR=/path/to/install make install as desired.

Troubleshooting

  1. If, when compiling a program, you see /usr/bin/ld: cannot find -lcs50: Add export LIBRARY_PATH=/usr/local/lib to your .bashrc.
  2. If, when compiling a program, you see fatal error: 'cs50.h' file not found: Add export C_INCLUDE_PATH=/usr/local/include to your .bashrc.
  3. If, when executing a program, you see error while loading shared libraries: libcs50.so.8: cannot open shared object file: No such file or directory: Add export LD_LIBRARY_PATH=/usr/local/lib to your .bashrc.

Close and reopen any terminal windows.

Usage

Link with -lcs50.

#include <cs50.h>

...
char c = get_char("Prompt: ");
double d = get_double("Prompt: ");
float f = get_float("Prompt: ");
int i = get_int("Prompt: ");
long l = get_long("Prompt: ");
string s = get_string("Prompt: ");

// deprecated as of fall 2017
long long ll = get_long_long("Prompt: ");

Documentation

See man get_* after installation, or CS50 Reference!

TODO

  • Add tests.

Contributors

libcs50's People

Contributors

cmlsharp avatar daveyproctor avatar dlloyd09 avatar dmalan avatar es80 avatar glennholloway avatar ivanjasenov avatar kzidane avatar mattangriffel avatar rbowden91 avatar rongxin-liu avatar theosotr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libcs50's Issues

Optimistic bounds check causes potential memory leaks and off-by-one or null pointer dereference

    // cs50.c#L280
    if (allocations == SIZE_MAX)
    {
        return NULL;
    }
    // ...
    // cs50.c#L365
    string *tmp = realloc(strings, sizeof(string) * (allocations + 1));
    // ...
    //cs50.c#L374
    strings[allocations] = s;

Optimistically, this code would be able to allocate SIZE_MAX elements of char * (L280).

Realistically, sizeof (string) is commonly greater than 1 and thus the multiplication at L365 is likely to cause unsigned integer wrapping long before then; at this point L365 will equate to string *tmp = realloc(strings, 0);. Either a/ an array suitable to allocate 0 char * elements will be created, or b/ strings will be freed and realloc will return a null pointer.

At L374 you have an assignment into a/ an array that can't contain any elements, or b/ a null pointer.

ptrs style

Something caught my in the code and that is the coding style of the pointers, not the way it's done in the lectures, the way I used to learn them like for example int* n, instead the more "old school" style int *n. Don't get me wrong guys, both are correct but this just does not correlates with the lecture style.
If change needed, just give me a green light.

Cont'd: Optimistic bounds check causes potential ... off-by-one ...

At L358 you have an implication that the string, excluding the '\0' terminator, can occupy SIZE_MAX bytes.

Then at L398 you have string s = realloc(buffer, size + 1);, where size + 1 (to include space for the '\0') will wrap back to 0 and... C11/7.22.3p1 seems to explain the rest nicely: "If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object."

When the returned pointer isn't a null pointer, it's accessed at L406 to assign the '\0'...

The issue is repeated within GetString.

Split pane replicates file contents from one pane to the other

Don't know if this happened previously (I just updated to v101)

If two individual files are open and the "Split pane in two columns (or rows)" command is invoked, a change or edit on one file causes that files contents to be replicated and replaces the contents of the other file.

This issue seems applicable only to the CS50 IDE, I tried to replicate the problem in my personal C9 workspace and the split pane works as expected.

Missing Release file

In Bash for Windows (which should basically just be Ubuntu?), I'm getting this after trying the apt-get update step:

W: The repository 'http://ppa.launchpad.net/cs50/ppa/ubuntu xenial Release' does not have a Release file.
N: Data from such a repository can't be authenticated and is therefore potentially dangerous to use.
N: See apt-secure(8) manpage for repository creation and user configuration details.
E: Failed to fetch http://ppa.launchpad.net/cs50/ppa/ubuntu/dists/xenial/main/binary-amd64/Packages 404 Not Found
E: Some index files failed to download. They have been ignored, or old ones used instead.

In the meantime I installed from source.

program_invocation_short_name missing on Mac OS

Use of program_invocation_short_name now causes compilation of the CS50 Library to fail on Mac OS:

Undefined symbols for architecture x86_64:
  "_program_invocation_short_name", referenced from:
      _eprintf in cs50.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Seems the variable is missing on Mac OS:
https://www.gnu.org/software/gnulib/manual/html_node/program_005finvocation_005fshort_005fname.html

A recommended fix is:

#undef GET_PROGRAM_NAME
#ifdef __GLIBC__
#   define GET_PROGRAM_NAME() program_invocation_short_name
#else /* *BSD and OS X */
#   include <stdlib.h>
#   define GET_PROGRAM_NAME() getprogname()
#endif

getprogname() missing on Windows(MinGW)

I use Windows 10 and MinGW-w64, gcc version is 6.1.0

gcc(MinGW-w64) shows:

error: implicit declaration of function 'getprogname' [-Werror=implicit-function-declaration]
#define program_invocation_short_name getprogname()
                                      ^

I couldn't fine the definition program_invocation_short_name or getprogname() in both stdlib.h and errno.h. Are there any alternative solutions?

get_string causes compile errors in newest deployed version

Update50'd to v100 and now get_string causes compile errors.

   ~/workspace/ $ make word
clang -fsanitize=integer -fsanitize=undefined -ggdb3 -O0 -std=c11 -Wall -Werror -Wextra -Wno-sign-compare -Wshadow    word.c  -lcrypt -lcs50 -lm -o word
word.c:7:16: error: missing field 'prompt' initializer [-Werror,-Wmissing-field-initializers]
    string s = get_string();
               ^
/usr/include/cs50.h:139:68: note: expanded from macro 'get_string'
#define get_string(...) get_string(&(struct prompt) {0, __VA_ARGS__})
                                                                   ^
1 error generated.
make: *** [word] Error 1

clang: error: linker command failed with exit code 1 (use -v to see invocation)

I install the cs50 in ubuntu using your instruction but when I compile some test file using clang I get this error.

machine@DESKTOP-7K00UM0:~/libcs50-7.1.2/tests$ clang eprintf.c
/tmp/eprintf-ecd946.o: In function main': eprintf.c:(.text+0x24): undefined reference to eprintf'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

56199 Segmentation fault

I'm using the cs50.h directly and getting a 56199 Segmentation fault.

Here is my hello.c:

#include "../../../github.com/cs50/lib50-c/src/cs50.h"
#include <stdio.h>

// Main project method
int main(void) {
    string s = get_string();
}

Build command is a simple make:

make hello

This also happens when I include the built header instead or if I have the header under /usr/include.
I'm working under Mac OS. Does this work only under linux?

Ressurect the /usr vs /usr/local discussion

Due to the recent number of students using OSX being unable to install the library due to /usr being write-protected, perhaps we should revisit this discussion. I would still hold that the rpm, pacman and deb targets should install to /usr since they will be managed by a package manager, but perhaps the install target should install to /usr/local since then the library would not be managed by a package manager.

At the very least, we could allow this behavior to be changed by an environment variable as some other libraries do where make install would default to /usr but something like INSTALL_DIR=/usr/local make install would cause the library to be installed in /usr/local so we don't have to tell those students to alter the makefile manually.

libcs50 clobbers errno

It is generally bad form for a library to change the value of errno without good reason (like reporting an error). get_long_long, get_int, get_float, get_double all clobber errno by resetting it to zero before running the relevant strto* function. From a practical perspective, this isn't a big deal since none of the CS50 psets require students to check errno. That said, if students are going to be encouraged to look at the source code, it would seem that it should follow best practices.

The most obvious way to fix this issue would be to add something like int errno_copy = errno; before errno is set to zero in each of the aforementioned functions and adding errno = errno_copy; after errno is checked. Unfortunately, with how the control flow is branched currently, there isn't a great way to do the latter without duplicating the line.

The duplication of a single line is not a big deal, however there is a kind of a fun way to avoid it. You could do something like this:

#define save_errno() __attribute__((cleanup(reset_errno))) int _save_errno = errno

static void reset_errno(int *e)
{
    errno = *e;
}

Then before each errno = 0 line in the afflicted functions, add the line save_errno(). For reference, the cleanup attribute allows you to specify a function that is run on a value when it goes out of scope.

The simpler solution is probably better but I thought this one was worth mentioning.

Add CMakeLists.txt file

I do not see a CMakeLists.txt file in the code.
I know it won't be possible to create a VS solution due to 'attribute' syntax error, but there is no problem creating CodeBlocks project and other make files.
People with MingGW can easily make use of CMakeLists file.
I tested it on my windows machine. It works fine. I can send a pull request if needed.

Installing the shared library correctly

@dmalan @glennholloway

error while loading shared libraries: libcs50.so: cannot open shared object file: No such file or directory

it looks like shared libraries are not being searched for in /usr/local/lib by default. here are the solutions that I could find:

per http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html

  1. modify LD_LIBRARY_PATH (useful for testing and development; shouldn't be modified by installation process) โ€” section 3.3.1.
  2. copy libcs50.so to a standard dir (e.g., /usr/lib) and running ldconfigโ€” section 3.5.

per a Unix SE question http://unix.stackexchange.com/questions/67781/use-shared-libraries-in-usr-local-lib
3. adding /usr/local/lib to /etc/ld.so.conf and running ldconfig.

per http://www.cyberciti.biz/faq/linux-setting-changing-library-path/
4. creating a conf file under the /etc/ld.so.conf.d, containing /usr/local/lib, and running ldconfig.

thoughts?

Unable to locate package libcs50

Could someone help me with this, please? I am using Ubuntu 16.04. When I follow steps from "read me", I got this:

sudo apt-get install libcs50
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package libcs50

Mac Installation

Currently, the Makefile does not support Mac. This includes incompatibilities with -soname, install -D and asciidoctor. Solutions to the first two problems can be found here and here. No idea on the last problem. There are most likely other problems, but this is where I stopped trying to fix it.

A lot of students in CS50 will most likely be using Macs, so I think this is important. I understand the Cloud9 platform is there, but I think this option should be available if the student desires. I'd be happy to work on this!

get_int error

After following the instructions on how to install the library, I sill can't seem to make a simple int.c file to work (following steps as showed in Week1 lecture of CS50). The installation process of the library was fine, no errors, but as i "make int", this pops up.

Undefined symbols for architecture x86_64:
"_get_int", referenced from:
_main in int-1cbe38.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [int] Error 1

Mac make install error:

I have the library at /usr/local/libcs50-8.0.5 with 5 items in it: Makefile, README, cs50.0 debian, docs, src, and tests.

I'm at the 'make install' step and getting this message:
rm -rf build debian/docs/ libcs50-* libcs50_*
cc -c -fPIC -std=c99 -Wall -o cs50.o src/cs50.c
error: unable to open output file 'cs50.o': 'Operation not permitted'
1 error generated.
make: *** [build] Error 1

Any ideas on what else I need to do? Thanks!

Complex, pervasive memory leaks throughout user input functions

Various library functions (get_char, get_double, get_float, get_int, get_long_long) make use of the function get_string which allocates memory; the functions then perform a transformation of that memory and return, without freeing the memory that was allocated, which is extremely unlikely to be used again, aside from being freed at the end of the program. The result may not appear via valgrind etc, but may have performance implications nonetheless, particularly when used in an infinite loop where the end of the program is unforeseeable. get_string also has this problem; there's no way for the caller to tell the library that they're finished with a string, so they (intentionally) leak its reference and it just... stays there... until the program exits.

Unfortunately this could impact the performance of certain testing methods (e.g. fuzzing) so drastically that programs written using these functions are likely to be untestable using those methods.

This issue is likely to be reproduced by a program that merely reads characters using get_char one after the other, and discards the reference to them in a typical manner... and piping input from /dev/random.

One fix might involve providing a function that deallocates and removes the reference of a string from the table. The C standard, for example, contains an equivalent function, called free.

cp: /usr/include/cs50.h: Operation not permitted

I spent around 4 hours trying to debug this, I can't seem to fix it. After downloading the latest release and extracting it seems that when I run make install it fails. I tried to run each individual command as sudo and still no luck. Using El Capitan OS, bash and Vim 8. This is also my first stab at working with C.

screen shot 2017-06-01 at 6 35 17 pm

Error messages when __attribute__ unsupported are non-obvious

A post was made on /r/cs50 recently about someone attempting to use the library on Windows but the build failing due to a syntax error on the use of __attribute__ as these are not supported by MSVC. It would be fairly trivial to add a check for this in cs50.h, the only question being whether this should result in a warning (since no features essential to the functionality of the library rely on __attribute__) or simply an error with our own user-friendly error message. The two solutions could look something like the following:

Warning:

#ifndef _GNUC
    // Can't use #warning because it is not available on MSVC
    #pragma message "Message explaining that the library relies on certain extensions and that certain things will not work (IO buffering, memory cleanup etc.)
    // Silence syntax errors
    #define __attribute__(X)
#endif

Error:

#ifndef _GNUC
    #error "Message like the above, perhaps suggesting that students who use Windows try MinGW"
#endif

change get_* to accept a prompt as argument

Instead of re-prompting user in cases of invalid input with Retry:, should instead just re-prompt user with argument. I.e.:

string get_string(string prompt);

Planned for Fall 2017.

tidy Makefile

Has gotten a bit unwieldy with so many variables. Harder to follow build process for students.

Ubuntu 17.04 is not supported

Trying to install the library in my Ubuntu 17.04 machine and also with some other machines with Ubuntu 17.4 but seems like in not yet supported because I'm always facing the following problem

W: The repository 'http://ppa.launchpad.net/cs50/ppa/ubuntu zesty Release' does not have a Release file.
E: Failed to fetch http://ppa.launchpad.net/cs50/ppa/ubuntu/dists/zesty/main/source/Sources  404  Not Found

which cause this problem E: Unable to locate package libcs50 when attempting to install it using sudo apt-get install libcs50 as mensioned in the REDME file.

Thanks in advance

Failed to install

I'm on Archlinux, I downloaded the latest release zip and tried installing it on my system.

[elliot@Tesla](libcs50-7.1.1) $ make install
rm -rf "build"
mkdir -p "build/usr/include" "build/usr/lib" "build/usr/share/man/man3" "build/usr/src"
gcc -c -fPIC -std=c99 -Wall -Werror -o "build/cs50.o" "src/cs50.c"
gcc -o "build/usr/lib/libcs50.so" -shared "build/cs50.o"
rm -f "build/cs50.o"
cp "src/cs50.h" "build/usr/include"
cp "src/cs50.c" "build/usr/src"
cp -r docs/* "build/usr/share/man/man3"
find "build" -type d -exec chmod 0755 {} +
find "build" -type f -exec chmod 0644 {} +
cp "build/usr/include/*" /usr/include
cp: cannot stat 'build/usr/include/*': No such file or directory
make: *** [Makefile:80: install] Error 1

So, it failed.
Then I tried compiling and installing manually and it worked. I suspect something is wrong in Makefile.

Double Freeing

@dmalan

while testing, detected a bug in lib50-c caused by the use of get_string in other lib50-c functions. basically because we're freeing inside these functions as well as the destructor, we're double-freeing.

assuming we still want to free get_string allocations, instead of calling free directly from these functions, good idea to use a linked-list-based data structure and have a deallocate function, that would take a string, search for it in the list, free, and update allocations?

something like:

void deallocate(string s) {
    string_node *prev = NULL;
    string_node *curr = root;
    while (curr && curr->s != s) {
        prev = curr;
        curr = curr->next;
    }

    if (curr) {
        if (prev)
            prev->next = curr->next;
        else
            root = NULL;

       free(curr);
       allocations--;
    }
}

(pardon any oversights above, if any; written on the fly)

that would, of course, be slower and consume more space (actually we'd have to handle realloc'ing less memory, or we'd end up with unused space), but is there a better solution? using scanf instead of get_string perhaps? though may be a bit of a headache too?

Make Install Error

I am not able to use the repository to install since I am using 17.10.
So, when I attempt to run make install (after running make), I get the following output:
sudo make install
rm -rf build debian/docs/ libcs50-* libcs50_*
cc -c -fPIC -std=c99 -Wall -o cs50.o src/cs50.c
cc -shared -Wl,-soname,libcs50.so.8 -o libcs50.so.8.0.5 cs50.o
rm -f cs50.o
ln -s libcs50.so.8.0.5 libcs50.so.8
ln -s libcs50.so.8 libcs50.so
install -D -m 644 src/cs50.h build/include/cs50.h
mkdir -p build/lib build/src/libcs50
mv libcs50.so* build/lib
cp -r src/* build/src/libcs50
asciidoctor -d manpage -b manpage -D debian/docs/ docs/*.adoc
/bin/sh: 1: asciidoctor: not found
Makefile:34: recipe for target 'docs' failed
make: *** [docs] Error 127

I am not sure how to fix this error. Please help and thank you.

Undefined behaviour caused by invalid values passed to character type (`<ctype.h>`) functions.

According to section 7.4 of the C11 standard, the argument of any <ctype.h> function "is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF".

However, in numerous functions (get_double, get_float, get_int, get_long_long) the argument to isspace is a char, of which the type isn't guaranteed to be an unsigned type and as a result, the value isn't guaranteed to "be representable as an unsigned char or shall equal the value of the macro EOF".

This kind of error has questions showing assertion errors on StackOverflow. It can be reproduced for such implementations by providing input characters that have negative, non-EOF values.

You need to cast that expression to an unsigned char, before you call isspace, in order to avoid this problem.

apt-get (unnecessarily?) tries to use a dialog-based front end on installation on Ubuntu 16.04

# apt-get install libcs50
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  libcs50
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 18.7 kB of archives.
After this operation, 85.0 kB of additional disk space will be used.
Get:1 http://ppa.launchpad.net/cs50/ppa/ubuntu xenial/main amd64 libcs50 amd64 8.1.0-0ubuntu16.04 [18.7 kB]
Fetched 18.7 kB in 0s (63.9 kB/s)
debconf: unable to initialize frontend: Dialog
debconf: (No usable dialog-like program is installed, so the dialog based frontend cannot be used. at /usr/share/perl5/Debconf/FrontEnd/Dialog.pm line 76, <> line 1.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.22.1 /usr/local/share/perl/5.22.1 /usr/lib/x86_64-linux-gnu/perl5/5.22 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl/5.22 /usr/share/perl/5.22 /usr/local/lib/site_perl /usr/lib/x86_64-linux-gnu/perl-base .) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7, <> line 1.)
debconf: falling back to frontend: Teletype
Selecting previously unselected package libcs50.
(Reading database ... 7616 files and directories currently installed.)
Preparing to unpack .../libcs50_8.1.0-0ubuntu16.04_amd64.deb ...
Unpacking libcs50 (8.1.0-0ubuntu16.04) ...
Processing triggers for libc-bin (2.23-0ubuntu9) ...
Setting up libcs50 (8.1.0-0ubuntu16.04) ...
Processing triggers for libc-bin (2.23-0ubuntu9) ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.